diff --git a/Modules/hashtable.h b/Include/internal/pycore_hashtable.h
similarity index 96%
rename from Modules/hashtable.h
rename to Include/internal/pycore_hashtable.h
index dbec23d2851..585f76b51d7 100644
--- a/Modules/hashtable.h
+++ b/Include/internal/pycore_hashtable.h
@@ -1,7 +1,12 @@
-#ifndef Py_HASHTABLE_H
-#define Py_HASHTABLE_H
-/* The whole API is private */
-#ifndef Py_LIMITED_API
+#ifndef Py_INTERNAL_HASHTABLE_H
+#define Py_INTERNAL_HASHTABLE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+# error "this header requires Py_BUILD_CORE define"
+#endif
/* Single linked list */
@@ -207,5 +212,7 @@ PyAPI_FUNC(int) _Py_hashtable_pop(
_Py_hashtable_pop(TABLE, sizeof(KEY), &(KEY), sizeof(DATA), &(DATA))
-#endif /* Py_LIMITED_API */
+#ifdef __cplusplus
+}
#endif
+#endif /* !Py_INTERNAL_HASHTABLE_H */
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 0d616d30448..d545a9efb3c 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -351,6 +351,7 @@ PYTHON_OBJS= \
Python/getversion.o \
Python/graminit.o \
Python/hamt.o \
+ Python/hashtable.o \
Python/import.o \
Python/importdl.o \
Python/initconfig.o \
@@ -1131,6 +1132,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_getopt.h \
$(srcdir)/Include/internal/pycore_gil.h \
$(srcdir)/Include/internal/pycore_hamt.h \
+ $(srcdir)/Include/internal/pycore_hashtable.h \
$(srcdir)/Include/internal/pycore_import.h \
$(srcdir)/Include/internal/pycore_initconfig.h \
$(srcdir)/Include/internal/pycore_interp.h \
diff --git a/Modules/Setup b/Modules/Setup
index 6bf142419de..87e73bac78f 100644
--- a/Modules/Setup
+++ b/Modules/Setup
@@ -132,7 +132,7 @@ faulthandler faulthandler.c
#
# bpo-35053: The module must be builtin since _Py_NewReference()
# can call _PyTraceMalloc_NewReference().
-_tracemalloc _tracemalloc.c hashtable.c
+_tracemalloc _tracemalloc.c
# PEG-based parser module -- slated to be *the* parser
_peg_parser _peg_parser.c
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c
index ea7e0127366..f22338166d0 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -2,7 +2,7 @@
#include "pycore_gc.h" // PyGC_Head
#include "pycore_pymem.h" // _Py_tracemalloc_config
#include "pycore_traceback.h"
-#include "hashtable.h"
+#include "pycore_hashtable.h"
#include "frameobject.h" // PyFrame_GetBack()
#include "clinic/_tracemalloc.c.h"
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index 73274ac9acf..b6b0cf3e991 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -181,6 +181,7 @@
+
@@ -335,7 +336,6 @@
-
@@ -462,6 +462,7 @@
+
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index 254c8fbbea5..10dfffba611 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -237,6 +237,9 @@
Include
+
+ Include
+
Include
@@ -1034,6 +1037,9 @@
Python
+
+ Modules
+
Python
@@ -1142,9 +1148,6 @@
Modules
-
- Modules
-
PC
diff --git a/Modules/hashtable.c b/Python/hashtable.c
similarity index 99%
rename from Modules/hashtable.c
rename to Python/hashtable.c
index 4a36a1e71cd..22b84590105 100644
--- a/Modules/hashtable.c
+++ b/Python/hashtable.c
@@ -45,7 +45,7 @@
*/
#include "Python.h"
-#include "hashtable.h"
+#include "pycore_hashtable.h"
#define HASHTABLE_MIN_SIZE 16
#define HASHTABLE_HIGH 0.50
diff --git a/Python/marshal.c b/Python/marshal.c
index b4429aea502..d2bff524f30 100644
--- a/Python/marshal.c
+++ b/Python/marshal.c
@@ -12,7 +12,7 @@
#include "longintrepr.h"
#include "code.h"
#include "marshal.h"
-#include "../Modules/hashtable.h"
+#include "pycore_hashtable.h"
/*[clinic input]
module marshal