It's perhaps a misconception to think the ..automodule :: directive applied to a package will automatically document sub-modules as members (by comparison with classes, variables, etc).
I just tested this but it can not be done using :private-members: and or :special-members:. Not by writing either option in the .. automodule:: directive corresponding to the package. (Trying to set both options in autodoc_default_options gives the same result.)
The following example of package and module layout:
C:.
│
└────your_package
│
│ public_module.py
│ _private_module.py
│ __init__.py
Using a .rst with a single .. automodule:: for the package:
Your package rst
================
.. automodule:: your_package
:members:
:undoc-members:
:private-members:
:special-members:
Minimal example _private_module.py with docstrings (public_module.py is the same except for the title):
"""Private module docstring."""
class PublicClass:
"""Docstring."""
pass
Does indeed give an empty documentation:

But if you remove the underscore from the module you get the exact same result.
I am trying to avoid parsing the package_name.rst via a script to add them
If you are generating the .rst files with sphinx-apidoc if using the -P flag:
-P, --private
Include “_private” modules.
New in version 1.2.
The generated files will include an .. automodule:: directive for the private modules, this does have the side-effect of also including the :private-members: option as noted in another post "Include __main__.py in sphinx-apidoc generated files".
Example explicitly including the .. automodule:: directives:
Your package rst
================
.. automodule:: your_package
:members:
:undoc-members:
.. automodule:: your_package.public_module
:members:
:undoc-members:
.. automodule:: your_package._private_module
:members:
:undoc-members:
The result:
