Это комбинаторная задача, которую лучше всего решить, используя itertools
.
from itertools import product
Разверните каждый элемент словаря в диапазон элементов:
range_items = [[(x, z) for z in range(y + 1)] for x,y in char_counts.items()]
#[[('a', 0), ('a', 1)], [('b', 0), ('b', 1), ('b', 2)]]
Возьмите декартово произведение каждый элемент из каждого диапазона с каждым элементом из всех других диапазонов:
products = product(*range_items)
#[(('a', 0), ('b', 0)), (('a', 0), ('b', 1)),...(('a', 1), ('b', 2))]
Удалите пары, у которых есть 0 счетчиков, и преобразуйте остатки в словари с пониманием слов:
[{k: v for k, v in pairs if v > 0} for pairs in products]
#[{}, {'b': 1}, {'b': 2}, {'a': 1}, {'a': 1, 'b': 1}, {'a': 1, 'b': 2}]