The key is to add some empty __init__py files in your dist, dist/dist1 and dist/dist1/apps directories.
I just tried putting together a toy project with the following structure:
.
├── dist
│   ├── dist1
│   │   ├── apps
│   │   │   ├── app_external
│   │   │   │   ├── admin.py
│   │   │   │   ├── apps.py
│   │   │   │   ├── __init__.py
│   │   │   │   ├── migrations
│   │   │   │   │   └── __init__.py
│   │   │   │   ├── models.py
│   │   │   │   ├── tests.py
│   │   │   │   └── views.py
│   │   │   └── __init__.py
│   │   └── __init__.py
│   └── __init__.py
└── src
    ├── app_internal
    │   ├── admin.py
    │   ├── apps.py
    │   ├── __init__.py
    │   ├── migrations
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── tests.py
    │   └── views.py
    ├── manage.py
    └── project
        ├── __init__.py
        ├── settings.py
        ├── urls.py
        └── wsgi.py
Notice that there is an empty __init__.py file in each directory under dist/. This is what makes each directory a Python package and make the Python test machinery to look for tests inside those directories.
Also notice that I have an internal app called app_internal and an external one called app_external in a directory structure similar to yours.
Both the app_internal and app_external have one fake test in the tests.py file.
app_external/tests.py content:
from django.test import TestCase
class ExternalTestCase(TestCase):
    def test_fake(self):
        self.assertTrue(False)
app_internal/tests.py content:
from django.test import TestCase
class InternalTestCase(TestCase):
    def test_fake(self):
        self.assertTrue(True)
Here we expect that the app_external test will fail and the app_internal test will succeed.
I can call the app_internal test by giving the usual command:
$ ./manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Destroying test database for alias 'default'...
And I can call the app_external test by giving the following command:
$ ./manage.py test ..
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_fake (dist.dist1.apps.app_external.tests.ExternalTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/augusto/develop/apps_outside/dist/dist1/apps/app_external/tests.py", line 10, in test_fake
    self.assertTrue(False)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
Destroying test database for alias 'default'...
Notice how I passed .. as the parameter to the test command.
This point to the parent directory with respect to src/, so it finds the dist package and every other package inside it. I expect that this will find all tests under your dist/ directory.
I can also run all internal and external tests at once by giving the following command:
$ ./manage.py test . ..
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.F
======================================================================
FAIL: test_fake (dist.dist1.apps.app_external.tests.ExternalTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/augusto/develop/apps_outside/dist/dist1/apps/app_external/tests.py", line 10, in test_fake
    self.assertTrue(False)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)
Destroying test database for alias 'default'...
I tested this using Django 1.11.23 and Python 2.7.12.