you can also use the buiilt-in (but undocumented) chart element function System`BarFunctionDump`TextureBar
with your custom textures:
ClearAll[texture]
texture[ms_: {Black, White}, m_: 100] := Texture @
RegionPlot[True, {x, 0, 1}, {y, 0, 1},
MeshFunctions -> {# - #2 &}, Mesh -> m, MeshStyle -> None,
MeshShading -> ms, Frame -> False, Axes -> False,
PlotRangePadding -> 0, ImagePadding -> 0, BoundaryStyle -> None];
Examples:
data1 = {0.408808, 0.0944349, 0.132875, 0.203982, 0.1599};
data2 = {0.183654, 0.228122, 0.164212, 0.12381, 0.300202};
styles1 = {Black, Purple, Blue, Green, Red};
styles2 = texture /@ Thread[{White, {LightRed, LightGreen, LightBlue,
LightPurple, LightGray}}];
{sdata1, sdata2} = MapThread[Style, #] & /@ { {data1, styles1}, {data2, styles2}};
BarChart[{sdata1, sdata2},
BarSpacing -> None,
PlotTheme -> "Detailed",
ChartLabels -> {{"Experiment", "Theory"}, None},
LabelStyle -> {18, GrayLevel[0]},
ImageSize -> Large,
ChartElementFunction -> System`BarFunctionDump`TextureBar]

Use
styles2b = texture[#, 40] & /@
Thread[{White, {LightRed, LightGreen, LightBlue, LightPurple, LightGray}}];
instead of styles2
to get

Use
styles2c = texture /@ {{Red, LightRed}, {Green, LightGreen}, {Blue, LightBlue},
{Purple, LightPurple}, {Gray, LightGray}}
to get

See also: This answer to a related Q/A