This is a trivial modification to my previous answer, in which the Bal variable keeps the number of as and bs the same.
ab_list2(ABs) :-
length(ABs, Len),
ab_list2_(Len, 0, [], ABs).
% 0 characters left to add
% 0 is the balance of as and bs, i.e. same amount of each
ab_list2_(0, 0, ABs, ABs).
ab_list2_(CharsToAdd, Bal, SoFar, ABs) :-
succ(CharsToAdd0, CharsToAdd),
add_char(Char, Inc),
Bal1 is Bal + Inc,
% Ensure that the balance can be zero for the complete list
CharsToAdd0 >= abs(Bal1),
ab_list2_(CharsToAdd0, Bal1, [Char|SoFar], ABs).
add_char(b, -1).
add_char(a, 1).
Result in swi-prolog:
?- time(findnsols(10, L, ab_list2(L), Ls)).
% 387 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 1297961 Lips)
Ls = [[], [a, b], [b, a], [a, a, b, b], [a, b, a, b], [b, a, a, b], [a, b, b, a], [b, a, b, a], [b, b, a, a], [a, a, a, b, b, b]]