Update: It turns out we can use a simple modifications of the option setting in OP for MeshFunctions to get the desired result:
1. Boole:
RegionPlot[{a, regions}, {p, 0, 10}, {q, 0, 10}, FrameLabel -> {p, q}, MaxRecursion -> 3, MeshFunctions -> {Boole[# + #2 >= 15] (#1 + #2) &, Boole[# + #2 >= 15] #1 &}, Mesh -> {30, 20}, MeshStyle -> {Orange, Green}, PlotLegends -> SwatchLegend[Automatic, Prepend[b, "Infeasible: " And @@ a], LegendMarkerSize -> {20, 20}]]

Alternatively, specify a list of values for each mesh function using, for example, Mesh -> {Range[15, 30, .5], Range[0, 10, .25]} to get

2. Piecewise:
We can also use
MeshFunctions -> {Piecewise[{{#1 + #2, # + #2 >= 15}}] &, Piecewise[{{#1, # + #2 >= 15}}] &}
to get the same result.
3. ConditionalExpression:
Finally, we can use ConditionalExpression if we use list of values for the Mesh option setting (and increase PlotPoints to remove artifacts):
RegionPlot[{a, regions}, {p, 0, 10}, {q, 0, 10}, FrameLabel -> {p, q}, MaxRecursion -> 3, MeshFunctions -> {ConditionalExpression[#1 + #2, # + #2 >= 15] &, ConditionalExpression[#1, # + #2 >= 15] &}, Mesh -> {Range[0, 20, .5], Range[0, 10, .5]}, PlotPoints -> 100, MeshStyle -> {Orange, Green}, PlotLegends -> SwatchLegend[Automatic, Prepend[b, "Infeasible: " And @@ a], LegendMarkerSize -> {20, 20}]]

Original answer:
An alternative approach: Use Texture[img] as the PlotStyle setting for the desired regions using img of your choice:
colors = ColorData[97] /@ Range[4]; texture1 = Texture[ExampleData[{"TestImage", "Mandrill"}]]; legendmarker1 = Graphics[{texture1, Polygon[{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, VertexTextureCoordinates -> Automatic]}]; RegionPlot[{a, regions}, {p, 0, 10}, {q, 0, 10}, FrameLabel -> {p, q}, MaxRecursion -> 3, PlotStyle -> Prepend[colors, texture1], TextureCoordinateFunction -> (Rescale[{#, #2}, {0, 10}/2] &), TextureCoordinateScaling -> False, PlotLegends -> SwatchLegend[Prepend[colors, texture1], Prepend[b, Row[{"Infeasible: ", And @@ a}]], LegendMarkers -> Prepend[ConstantArray[Automatic, Length@b], legendmarker1], LegendMarkerSize -> {30, 30}]]

To use a hatched image instead of "Mandrill", you can use a simplified version of the function hatchingF from this answer
ClearAll[hatchedTexture] hatchedTexture[ps_: None, cols_: {Red, Orange}, m_: {10, 10}, t_: AbsoluteThickness[5]] := RegionPlot[True, {x, 0, 1}, {y, 0, 1}, MeshFunctions -> {# + #2 &, # &}, Mesh -> m, MeshShading -> None, MeshStyle -> (Directive[t, #] & /@ cols), Frame -> False, PlotRangePadding -> 0, PlotStyle -> ps, BaseStyle -> EdgeForm[], BoundaryStyle -> None]
Replace texture1 and legendmarker1 above with
texture2 = Texture[Rasterize @ hatchedTexture[]]; legendmarker2 = Graphics[{texture2, Polygon[coords = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}, VertexTextureCoordinates -> (coords/2)]}];
to get

Use texture2 = Texture[Rasterize @ hatchedTexture[LightBlue]] to get

Use texture2 = Texture[Rasterize @ hatchedTexture[texture1, {Black, Black}]] if you wish to be cruel and put "Mandrill" behind bars:

PlotLegends -> ....is irrelevant for the question asked. Finally, I'm quite surprised thatMeshFunctions -> ConditionalExpression[{#1 + #2 &, #1 &}, -15 + #1 + #2 >= 0 &](and its variations) doesn't work. $\endgroup$