diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 02d024d927ec..5318d40d12b4 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -327,7 +327,6 @@ static struct btd_profile batt_profile = {
 	.device_remove	= batt_remove,
 	.accept		= batt_accept,
 	.disconnect	= batt_disconnect,
-	.external	= true,
 };
 
 static int batt_init(void)
diff --git a/profiles/deviceinfo/deviceinfo.c b/profiles/deviceinfo/deviceinfo.c
index b6dc0ab2e207..0cdf2947e0a3 100644
--- a/profiles/deviceinfo/deviceinfo.c
+++ b/profiles/deviceinfo/deviceinfo.c
@@ -138,7 +138,6 @@ static int deviceinfo_disconnect(struct btd_service *service)
 static struct btd_profile deviceinfo_profile = {
 	.name		= "deviceinfo",
 	.remote_uuid	= DEVICE_INFORMATION_UUID,
-	.external	= true,
 	.device_probe	= deviceinfo_probe,
 	.device_remove	= deviceinfo_remove,
 	.accept		= deviceinfo_accept,
diff --git a/src/btd.h b/src/btd.h
index 07205aa69486..a443f66f6cd8 100644
--- a/src/btd.h
+++ b/src/btd.h
@@ -42,6 +42,12 @@ enum sc_mode_t {
 	SC_ONLY,
 };
 
+enum bt_gatt_export_t {
+	BT_GATT_EXPORT_OFF,
+	BT_GATT_EXPORT_READ_ONLY,
+	BT_GATT_EXPORT_READ_WRITE,
+};
+
 struct btd_br_defaults {
 	uint16_t	page_scan_type;
 	uint16_t	page_scan_interval;
@@ -147,6 +153,7 @@ struct btd_opts {
 	uint16_t	gatt_mtu;
 	uint8_t		gatt_channels;
 	bool		gatt_client;
+	enum bt_gatt_export_t gatt_export;
 	enum mps_mode_t	mps;
 
 	struct btd_avdtp_opts avdtp;
diff --git a/src/gatt-client.c b/src/gatt-client.c
index a67e04eee81e..6f22bbb490a7 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -66,6 +66,7 @@ struct btd_gatt_client {
 struct service {
 	struct btd_gatt_client *client;
 	bool primary;
+	bool claimed;
 	uint16_t start_handle;
 	uint16_t end_handle;
 	bt_uuid_t uuid;
@@ -616,6 +617,14 @@ static DBusMessage *descriptor_write_value(DBusConnection *conn,
 	if (parse_options(&iter, &offset, NULL))
 		return btd_error_invalid_args(msg);
 
+	/*
+	 * Check if service was previously claimed by a plugin and if we shall
+	 * consider it read-only, in that case return not authorized.
+	 */
+	if (desc->chrc->service->claimed &&
+			btd_opts.gatt_export == BT_GATT_EXPORT_READ_ONLY)
+		return btd_error_not_authorized(msg);
+
 	/*
 	 * Don't allow writing to Client Characteristic Configuration
 	 * descriptors. We achieve this through the StartNotify and StopNotify
@@ -1046,6 +1055,14 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn,
 	if (parse_options(&iter, &offset, &type))
 		return btd_error_invalid_args(msg);
 
+	/*
+	 * Check if service was previously claimed by a plugin and if we shall
+	 * consider it read-only, in that case return not authorized.
+	 */
+	if (chrc->service->claimed &&
+			btd_opts.gatt_export == BT_GATT_EXPORT_READ_ONLY)
+		return btd_error_not_authorized(msg);
+
 	/*
 	 * Decide which write to use based on characteristic properties. For now
 	 * we don't perform signed writes since gatt-client doesn't support them
@@ -1295,6 +1312,14 @@ static DBusMessage *characteristic_acquire_write(DBusConnection *conn,
 	if (!gatt)
 		return btd_error_failed(msg, "Not connected");
 
+	/*
+	 * Check if service was previously claimed by a plugin and if we shall
+	 * consider it read-only, in that case return not authorized.
+	 */
+	if (chrc->service->claimed &&
+			btd_opts.gatt_export == BT_GATT_EXPORT_READ_ONLY)
+		return btd_error_not_authorized(msg);
+
 	if (chrc->write_io)
 		return btd_error_not_permitted(msg, "Write acquired");
 
@@ -1954,6 +1979,7 @@ static struct service *service_create(struct gatt_db_attribute *attr,
 	service->chrcs = queue_new();
 	service->incl_services = queue_new();
 	service->client = client;
+	service->claimed = gatt_db_service_get_claimed(attr);
 
 	gatt_db_attribute_get_service_data(attr, &service->start_handle,
 							&service->end_handle,
@@ -2097,8 +2123,15 @@ static void export_service(struct gatt_db_attribute *attr, void *user_data)
 	struct btd_gatt_client *client = user_data;
 	struct service *service;
 
-	if (gatt_db_service_get_claimed(attr))
-		return;
+	if (gatt_db_service_get_claimed(attr)) {
+		switch (btd_opts.gatt_export) {
+		case BT_GATT_EXPORT_OFF:
+			return;
+		case BT_GATT_EXPORT_READ_ONLY:
+		case BT_GATT_EXPORT_READ_WRITE:
+			break;
+		}
+	}
 
 	service = service_create(attr, client);
 	if (!service)
diff --git a/src/main.c b/src/main.c
index 41c3271a7457..b92b22e41d4c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -148,6 +148,7 @@ static const char *gatt_options[] = {
 	"ExchangeMTU",
 	"Channels",
 	"Client",
+	"ExportClaimedServices",
 	NULL
 };
 
@@ -1066,6 +1067,33 @@ static void parse_gatt_cache(GKeyFile *config)
 	g_free(str);
 }
 
+static enum bt_gatt_export_t parse_gatt_export_str(const char *str)
+{
+	if (!strcmp(str, "no") || !strcmp(str, "false") ||
+				!strcmp(str, "off")) {
+		return BT_GATT_EXPORT_OFF;
+	} else if (!strcmp(str, "read-only")) {
+		return BT_GATT_EXPORT_READ_ONLY;
+	} else if (!strcmp(str, "read-write")) {
+		return BT_GATT_EXPORT_READ_WRITE;
+	}
+
+	DBG("Invalid value for ExportClaimedServices=%s", str);
+	return BT_GATT_EXPORT_READ_ONLY;
+}
+
+static void parse_gatt_export(GKeyFile *config)
+{
+	char *str = NULL;
+
+	parse_config_string(config, "GATT", "ExportClaimedServices", &str);
+	if (!str)
+		return;
+
+	btd_opts.gatt_export = parse_gatt_export_str(str);
+	g_free(str);
+}
+
 static void parse_gatt(GKeyFile *config)
 {
 	parse_gatt_cache(config);
@@ -1075,6 +1103,7 @@ static void parse_gatt(GKeyFile *config)
 	parse_config_u8(config, "GATT", "Channels", &btd_opts.gatt_channels,
 				1, 5);
 	parse_config_bool(config, "GATT", "Client", &btd_opts.gatt_client);
+	parse_gatt_export(config);
 }
 
 static void parse_csis_sirk(GKeyFile *config)
@@ -1219,6 +1248,7 @@ static void init_defaults(void)
 	btd_opts.gatt_mtu = BT_ATT_MAX_LE_MTU;
 	btd_opts.gatt_channels = 1;
 	btd_opts.gatt_client = true;
+	btd_opts.gatt_export = BT_GATT_EXPORT_READ_ONLY;
 
 	btd_opts.avdtp.session_mode = BT_IO_MODE_BASIC;
 	btd_opts.avdtp.stream_mode = BT_IO_MODE_BASIC;
diff --git a/src/main.conf b/src/main.conf
index fff13ed2ff31..80e72e18f749 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -262,6 +262,11 @@
 # Default to 1
 #Channels = 1
 
+# Export claimed services by plugins
+# Possible values: no, read-only, read-write
+# Default: read-only
+#ExportClaimedServices = read-only
+
 [CSIS]
 # SIRK - Set Identification Resolution Key which is common for all the
 # sets. They SIRK key is used to identify its sets. This can be any
