diff --git a/src/device.c b/src/device.c
index 0deee2707..bd8c80032 100644
--- a/src/device.c
+++ b/src/device.c
@@ -275,6 +275,7 @@ struct btd_device {
 	gboolean	auto_connect;
 	gboolean	disable_auto_connect;
 	gboolean	general_connect;
+	gboolean	allow_internal_profiles;
 
 	bool		legacy;
 	int8_t		rssi;
@@ -294,6 +295,10 @@ static const uint16_t uuid_list[] = {
 static int device_browse_gatt(struct btd_device *device, DBusMessage *msg);
 static int device_browse_sdp(struct btd_device *device, DBusMessage *msg);
 
+static void gatt_service_added(struct gatt_db_attribute *attr, void *user_data);
+static void gatt_service_removed(struct gatt_db_attribute *attr,
+					void *user_data);
+
 static struct bearer_state *get_state(struct btd_device *dev,
 							uint8_t bdaddr_type)
 {
@@ -436,6 +441,9 @@ static gboolean store_device_info_cb(gpointer user_data)
 	g_key_file_set_boolean(key_file, "General", "Blocked",
 							device->blocked);
 
+	g_key_file_set_boolean(key_file, "General", "AllowInternalProfiles",
+				device->allow_internal_profiles);
+
 	if (device->wake_override != WAKE_FLAG_DEFAULT) {
 		g_key_file_set_boolean(key_file, "General", "WakeAllowed",
 				       device->wake_override ==
@@ -1468,6 +1476,71 @@ static gboolean dev_property_wake_allowed_exist(
 	return device_get_wake_support(device);
 }
 
+static gboolean
+dev_property_get_allow_internal_profiles(const GDBusPropertyTable *property,
+						DBusMessageIter *iter,
+						void *data)
+{
+	struct btd_device *device = data;
+	dbus_bool_t allow_internal_profiles = device->allow_internal_profiles;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN,
+					&allow_internal_profiles);
+
+	return TRUE;
+}
+
+static void
+dev_property_set_allow_internal_profiles(const GDBusPropertyTable *property,
+						DBusMessageIter *value,
+						GDBusPendingPropertySet id,
+						void *data)
+{
+	struct btd_device *device = data;
+	dbus_bool_t b;
+
+	if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) {
+		g_dbus_pending_property_error(
+			id, ERROR_INTERFACE ".InvalidArguments",
+			"Invalid arguments in method call");
+		return;
+	}
+
+	if (device->le_state.connected || device->bredr_state.connected) {
+		g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed",
+					"Device is connected");
+		return;
+	}
+
+	dbus_message_iter_get_basic(value, &b);
+
+	device->allow_internal_profiles = b;
+
+	/* Remove GATT client cache */
+	gatt_db_unregister(device->db, device->db_id);
+	btd_gatt_client_destroy(device->client_dbus);
+	gatt_db_unref(device->db);
+
+	device->db = gatt_db_new();
+	device->client_dbus = btd_gatt_client_new(device);
+	device->db_id = gatt_db_register(device->db, gatt_service_added,
+			gatt_service_removed, device, NULL);
+
+	/* Re-probe all profiles */
+	while (device->services != NULL) {
+		struct btd_service *service = device->services->data;
+
+		device->services = g_slist_remove(device->services, service);
+		service_remove(service);
+	}
+
+	device_probe_profiles(device, device->uuids);
+
+	/* Update D-Bus property and reply client */
+	g_dbus_emit_property_changed(dbus_conn, device->path, DEVICE_INTERFACE,
+						"AllowInternalProfiles");
+	g_dbus_pending_property_success(id);
+}
 
 static gboolean disconnect_all(gpointer user_data)
 {
@@ -2944,6 +3017,9 @@ static const GDBusPropertyTable device_properties[] = {
 	{ "WakeAllowed", "b", dev_property_get_wake_allowed,
 				dev_property_set_wake_allowed,
 				dev_property_wake_allowed_exist },
+	{ "AllowInternalProfiles", "b",
+				dev_property_get_allow_internal_profiles,
+				dev_property_set_allow_internal_profiles },
 	{ }
 };
 
@@ -3196,6 +3272,7 @@ static void load_info(struct btd_device *device, const char *local,
 	char *str;
 	gboolean store_needed = FALSE;
 	gboolean blocked;
+	gboolean allow_internal_profiles;
 	gboolean wake_allowed;
 	char **uuids;
 	int source, vendor, product, version;
@@ -3283,6 +3360,20 @@ next:
 	if (blocked)
 		device_block(device, FALSE);
 
+	/* Load allow internal profiles */
+	allow_internal_profiles = g_key_file_get_boolean(
+		key_file, "General", "AllowInternalProfiles", &gerr);
+	if (!gerr) {
+		device->allow_internal_profiles = allow_internal_profiles;
+	} else {
+		/* Old config doesn't contain this item, so set it to true to
+		 * match the previous default behavior.
+		 */
+		device->allow_internal_profiles = true;
+		g_error_free(gerr);
+		gerr = NULL;
+	}
+
 	/* Load device profile list */
 	uuids = g_key_file_get_string_list(key_file, "General", "Services",
 						NULL, NULL);
@@ -3782,6 +3873,9 @@ static bool device_match_profile(struct btd_device *device,
 							bt_uuid_strcmp) == NULL)
 		return false;
 
+	if (!device->allow_internal_profiles && !profile->external)
+		return false;
+
 	return true;
 }
 
@@ -4055,6 +4149,8 @@ static struct btd_device *device_new(struct btd_adapter *adapter,
 
 	device->adapter = adapter;
 	device->temporary = true;
+	device->allow_internal_profiles =
+		main_opts.default_allow_internal_profiles;
 
 	device->db_id = gatt_db_register(device->db, gatt_service_added,
 					gatt_service_removed, device, NULL);
diff --git a/src/hcid.h b/src/hcid.h
index c21ac9980..82ea0cb14 100644
--- a/src/hcid.h
+++ b/src/hcid.h
@@ -114,6 +114,8 @@ struct main_opts {
 	uint8_t		key_size;
 
 	enum jw_repairing_t jw_repairing;
+
+	gboolean	default_allow_internal_profiles;
 };
 
 extern struct main_opts main_opts;
diff --git a/src/main.c b/src/main.c
index bacb44197..30218f8d0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -89,6 +89,7 @@ static const char *supported_options[] = {
 	"FastConnectable",
 	"Privacy",
 	"JustWorksRepairing",
+	"DefaultAllowInternalProfiles",
 	NULL
 };
 
@@ -615,6 +616,13 @@ static void parse_config(GKeyFile *config)
 	else
 		main_opts.fast_conn = boolean;
 
+	boolean = g_key_file_get_boolean(config, "General",
+					"DefaultAllowInternalProfiles", &err);
+	if (err)
+		g_clear_error(&err);
+	else
+		main_opts.default_allow_internal_profiles = boolean;
+
 	str = g_key_file_get_string(config, "GATT", "Cache", &err);
 	if (err) {
 		DBG("%s", err->message);
@@ -691,6 +699,8 @@ static void init_defaults(void)
 	main_opts.gatt_cache = BT_GATT_CACHE_ALWAYS;
 	main_opts.gatt_mtu = BT_ATT_MAX_LE_MTU;
 	main_opts.gatt_channels = 3;
+
+	main_opts.default_allow_internal_profiles = true;
 }
 
 static void log_handler(const gchar *log_domain, GLogLevelFlags log_level,
diff --git a/src/main.conf b/src/main.conf
index 6a6f7d4b4..497394395 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -77,6 +77,10 @@
 # Defaults to "never"
 #JustWorksRepairing = never
 
+# The default value of "AllowInternalProfiles" property in org.bluez.Device1
+# interface. Defaults to 'true'.
+#DefaultAllowInternalProfiles = true
+
 [Controller]
 # The following values are used to load default adapter parameters.  BlueZ loads
 # the values into the kernel before the adapter is powered if the kernel
