diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4a02d340f92e549043c0a25b1893c8900f0a0a58..f26486f84123007bb026e9a5ed9fc9ccdfbf49cf 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,11 +1,14 @@
-include:
-  - project: 'iopsys/gitlab-ci-pipeline'
-    file: '/static-code-analysis.yml'
-
 variables:
   DEBUG: 'TRUE'
   SOURCE_FOLDER: "."
+  FLAWFINDER_OPTIONS: "-m 4 --error-level=5"
+  CPD_OPTIONS: "--minimum-tokens 200 --language c --exclude ./daemon/json_rpc/ --files"
   CPPCHECK_OPTIONS: " --enable=performance,portability,information --inline-suppr"
 
+include:
+  - project: 'iopsys/gitlab-ci-pipeline'
+    file: '/static-code-analysis.yml'
+    ref: '0.31'
+
 stages:
     - static_code_analysis
diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt
index 498a99244c4747a69559ae76c41e463c7fe05ec3..8cdc38e616694703858f3db82c01a6d5dd1c9b97 100644
--- a/daemon/CMakeLists.txt
+++ b/daemon/CMakeLists.txt
@@ -3,7 +3,10 @@ cmake_minimum_required(VERSION 3.0)
 PROJECT(tr104daemon C)
 
 OPTION(DM_ENABLE_UBUS "Build with UBus Support" OFF)
+OPTION(DM_ENABLE_JSON_RPC "Build with JSON-RPC Support" OFF)
 
 IF(DM_ENABLE_UBUS)
 	add_subdirectory(ubus)
-ENDIF(DM_ENABLE_UBUS)
+ELSEIF(DM_ENABLE_JSON_RPC)
+	add_subdirectory(json_rpc)
+ENDIF()
diff --git a/daemon/json_rpc/CMakeLists.txt b/daemon/json_rpc/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ce21d5b07f41c6a67c5ef39ea0d5ba4139757770
--- /dev/null
+++ b/daemon/json_rpc/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.0)
+
+PROJECT(tr104d)
+
+ADD_DEFINITIONS(-fstrict-aliasing -Wall -Wextra -Werror -Wformat -Wformat-signedness -fPIC -D_GNU_SOURCE)
+ADD_DEFINITIONS(-DBBF_VENDOR_PREFIX="${BBF_VENDOR_PREFIX}")
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR}")
+
+OPTION(DM_ENABLE_DECT "Enable DECT support" OFF)
+
+IF(DM_ENABLE_DECT)
+	ADD_DEFINITIONS(-DDM_ENABLE_DECT)
+ENDIF(DM_ENABLE_DECT)
+
+FILE(GLOB BBF_SOURCES *.c)
+ADD_EXECUTABLE(tr104d ${BBF_SOURCES})
+TARGET_LINK_LIBRARIES(tr104d dmtree dm ubus ubox blobmsg_json uci json-c json_hal_server dl rt)
+
+INSTALL(TARGETS tr104d DESTINATION usr/sbin)
diff --git a/daemon/json_rpc/add_delete.c b/daemon/json_rpc/add_delete.c
new file mode 100644
index 0000000000000000000000000000000000000000..e0e465f1061d9625fc1f40027a728d1731053c41
--- /dev/null
+++ b/daemon/json_rpc/add_delete.c
@@ -0,0 +1,109 @@
+/*
+ * add_delete.c: Add/Delete handler for bbfdmd
+ *
+ * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu>
+ *
+ * See LICENSE file for license related information.
+ */
+
+#include "common.h"
+#include "add_delete.h"
+#include "get_helper.h"
+#include "service_helper.h"
+
+int bbfdm_add_object(struct dmctx *bbf_ctx)
+{
+	char cur_ch;
+	int ret = 0;
+	struct dmctx bbf_ctx_inst, bbf_ctx_add_obj;
+	char *str = bbf_ctx->in_param, *multi_obj_str = NULL;
+
+	INFO("Req to add object |%s|", bbf_ctx->in_param);
+	memset(&bbf_ctx_inst, 0, sizeof(bbf_ctx_inst));
+	bbf_sub_init(&bbf_ctx_inst);
+	bbf_ctx_inst.in_param = bbf_ctx->in_param;
+	memset(&bbf_ctx_add_obj, 0, sizeof(bbf_ctx_add_obj));
+	bbf_sub_init(&bbf_ctx_add_obj);
+	bbf_ctx_add_obj.in_param = bbf_ctx->in_param;
+
+	while (!ret && (str = DM_STRCHR(str, '.')))
+	{
+		cur_ch = str[1];
+		str[1] = '\0';
+		ret = bbfdm_cmd_exec(&bbf_ctx_inst, BBF_INSTANCES);
+
+		if (ret && multi_obj_str) {
+			int ch = multi_obj_str[1];
+
+			multi_obj_str[1] = '\0';
+			if ((ret = bbfdm_cmd_exec(&bbf_ctx_add_obj, BBF_ADD_OBJECT))) {
+				ERR("addObject: failed adding object (%s)", bbf_ctx_add_obj.in_param);
+			}
+			multi_obj_str[1] = ch;
+		}
+
+	    str[1] = cur_ch;
+	    if ( cur_ch >= '1' && cur_ch <= '9')
+		    multi_obj_str = str;
+	    else
+		    multi_obj_str = NULL;
+	    str++;
+    }
+    bbf_sub_cleanup(&bbf_ctx_inst);
+    bbf_sub_cleanup(&bbf_ctx_add_obj);
+
+    return ret;
+}
+
+int del_object(char *obj_path)
+{
+	struct dmctx bbf_ctx;
+	int ret = 0;
+
+	memset(&bbf_ctx, 0, sizeof(bbf_ctx));
+	bbf_init(&bbf_ctx);
+	bbf_ctx.in_param = obj_path;
+
+	INFO("Req to del object |%s|", obj_path);
+	if ((ret = bbfdm_cmd_exec(&bbf_ctx, BBF_DEL_OBJECT)))
+		ERR("Failed deleting (%s)", obj_path);
+
+	bbf_cleanup(&bbf_ctx);
+
+	return ret;
+}
+
+int bbfdm_del_object(const json_object *jmsg, int param_count, json_object *jreply)
+{
+	int i;
+	hal_param_t param_request;
+
+	if (jmsg == NULL || jreply == NULL) {
+		ERR("getParameters cb: invalid memory");
+		return RETURN_ERR;
+	}
+
+	for (i = 0; i < param_count; i++) {
+		/* Unpack the JSON and populate the data into request_param object */
+		if (json_hal_get_param((json_object *)jmsg, i, GET_REQUEST_MESSAGE,
+			&param_request) != RETURN_OK) {
+			ERR("deleteObject cb: failed getting parameter");
+			return RETURN_ERR;
+		}
+
+		del_object(param_request.name);
+		if (json_hal_add_param(jreply, GET_RESPONSE_MESSAGE, &param_request)
+			!= RETURN_OK) {
+			ERR("deleteObject cb: failed adding response");
+			return RETURN_ERR;
+		}
+	}
+
+	restart_services();
+
+	return RETURN_OK;
+}
+
+
diff --git a/daemon/json_rpc/add_delete.h b/daemon/json_rpc/add_delete.h
new file mode 100644
index 0000000000000000000000000000000000000000..6329c3d54c803dbc71472066d491413d20f87605
--- /dev/null
+++ b/daemon/json_rpc/add_delete.h
@@ -0,0 +1,10 @@
+#ifndef ADD_DELETE_H
+#define ADD_DELETE_H
+
+#include "common.h"
+#include <json_hal_server.h>
+
+int bbfdm_add_object(struct dmctx *bbf_ctx);
+int bbfdm_del_object(const json_object *jmsg, int param_count, json_object *jreply);
+
+#endif /* ADD_DELETE_H */
diff --git a/daemon/json_rpc/cli.c b/daemon/json_rpc/cli.c
new file mode 100644
index 0000000000000000000000000000000000000000..7b392cb80a1be423c9351cd998c123ea613bd629
--- /dev/null
+++ b/daemon/json_rpc/cli.c
@@ -0,0 +1,381 @@
+/*
+ * cli.c: Cli command for bbfdmd
+ *
+ * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
+ * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu>
+ *
+ * See LICENSE file for license related information.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "common.h"
+#include "libdmtree/dmapi.h"
+#include "libdmtree/dmjson.h"
+#include "libdmtree/dmentry.h"
+
+#define UNUSED  __attribute__((unused))
+
+extern DMOBJ *DEAMON_DM_ROOT_OBJ;
+extern DM_MAP_VENDOR *DEAMON_DM_VENDOR_EXTENSION[2];
+extern DM_MAP_VENDOR_EXCLUDE *DEAMON_DM_VENDOR_EXTENSION_EXCLUDE;
+
+extern int bbfdm_load_deamon_config(void);
+
+typedef struct {
+	struct dmctx bbf_ctx;
+	unsigned int instance_mode;
+	unsigned int proto;
+	char in_name[128];
+	char in_type[8];
+	char out_type[8];
+	char *cmd;
+} cli_data_t;
+
+typedef struct {
+    char *name;
+    int num_args;
+    int (*exec_cmd)(cli_data_t *cli_data, char *argv[]);
+    char *usage;
+} cli_cmd_t;
+
+static int cli_exec_help(cli_data_t *cli_data UNUSED, char *argv[] UNUSED);
+static int cli_exec_get(cli_data_t *cli_data, char *argv[]);
+static int cli_exec_set(cli_data_t *cli_data, char *argv[]);
+static int cli_exec_add(cli_data_t *cli_data, char *argv[]);
+static int cli_exec_del(cli_data_t *cli_data, char *argv[]);
+static int cli_exec_instances(cli_data_t *cli_data, char *argv[]);
+static int cli_exec_schema(cli_data_t *cli_data, char *argv[]);
+
+cli_cmd_t cli_commands[] = {
+//    Name    NumArgs   Exec callback     Usage String
+	{ "help",    0,		cli_exec_help,  "help" },
+	{ "get",     1, 	cli_exec_get,   "get [path-expr]" },
+	{ "set",     2, 	cli_exec_set,   "set [path-expr] [value]"},
+	{ "add",     1, 	cli_exec_add,   "add [object]"},
+	{ "del",     1, 	cli_exec_del,   "del [path-expr]"},
+	{ "instances", 1, 	cli_exec_instances,   "instances [path-expr]" },
+	{ "schema",    1,  	cli_exec_schema,  "schema [path-expr]"},
+};
+
+static int bbfdm_load_cli_config(cli_data_t *cli_data)
+{
+	cli_data->proto = BBFDM_BOTH;
+	cli_data->instance_mode = INSTANCE_MODE_NUMBER;
+	snprintf(cli_data->out_type, 8, "%s", "CLI");
+	snprintf(cli_data->in_type, 8, "%s", "DotSO");
+	return 0;
+}
+
+static int cli_exec_help(cli_data_t *cli_data UNUSED, char *argv[] UNUSED)
+{
+	printf("Valid commands:\n");
+
+	// Print out the help usage of all commands
+	for (size_t i = 0; i < ARRAY_SIZE(cli_commands); i++) {
+		printf("   %s\n", cli_commands[i].usage);
+	}
+
+	return EXIT_SUCCESS;
+}
+
+static int in_dotso_out_cli_exec_get(cli_data_t *cli_data, char *argv[])
+{
+	int err = EXIT_SUCCESS;
+
+	cli_data->bbf_ctx.in_param = argv[0];
+
+	err = bbf_entry_method(&cli_data->bbf_ctx, BBF_GET_VALUE);
+	if (!err) {
+		struct dm_parameter *n;
+
+		list_for_each_entry(n, &cli_data->bbf_ctx.list_parameter, list) {
+			printf("%s => %s\n", n->name, n->data);
+		}
+	} else {
+		printf("ERROR: %d retrieving %s\n", err, cli_data->bbf_ctx.in_param);
+		err = EXIT_FAILURE;
+	}
+
+	return err;
+}
+
+static int cli_exec_get(cli_data_t *cli_data, char *argv[])
+{
+	int err = EXIT_SUCCESS;
+
+	if (strcasecmp(cli_data->in_type, "DotSO") == 0 || strcasecmp(cli_data->in_type, "JSON") == 0)
+		err = in_dotso_out_cli_exec_get(cli_data, argv);
+	else
+		err = EXIT_FAILURE;
+
+	return err;
+}
+
+static int in_dotso_out_cli_exec_set(cli_data_t *cli_data, char *argv[])
+{
+	int err = EXIT_SUCCESS;
+
+	cli_data->bbf_ctx.in_param = argv[0];
+	cli_data->bbf_ctx.in_value = argv[1];
+
+	err = bbf_entry_method(&cli_data->bbf_ctx, BBF_SET_VALUE);
+	if (!err) {
+		printf("%s => Set value is successfully done\n", cli_data->bbf_ctx.in_param);
+		bbf_entry_restart_services(NULL, true);
+	} else {
+		printf("ERROR: %d retrieving %s => %s\n", err, cli_data->bbf_ctx.in_param, cli_data->bbf_ctx.in_value);
+		bbf_entry_revert_changes(NULL);
+		err = EXIT_FAILURE;
+	}
+
+	return err;
+}
+
+static int cli_exec_set(cli_data_t *cli_data, char *argv[])
+{
+	int err = EXIT_SUCCESS;
+
+	if (strcasecmp(cli_data->in_type, "DotSO") == 0 || strcasecmp(cli_data->in_type, "JSON") == 0)
+		err = in_dotso_out_cli_exec_set(cli_data, argv);
+	else
+		err = EXIT_FAILURE;
+
+	return err;
+}
+
+static int in_dotso_out_cli_exec_add(cli_data_t *cli_data, char *argv[])
+{
+	int err = EXIT_SUCCESS;
+
+	cli_data->bbf_ctx.in_param = argv[0];
+
+	err = bbf_entry_method(&cli_data->bbf_ctx, BBF_ADD_OBJECT);
+	if (!err) {
+		printf("Added %s%s.\n", cli_data->bbf_ctx.in_param, cli_data->bbf_ctx.addobj_instance);
+		bbf_entry_restart_services(NULL, true);
+	} else {
+		printf("ERROR: %d retrieving %s\n", err, cli_data->bbf_ctx.in_param);
+		bbf_entry_revert_changes(NULL);
+		err = EXIT_FAILURE;
+	}
+
+	return err;
+}
+
+static int cli_exec_add(cli_data_t *cli_data, char *argv[])
+{
+	int err = EXIT_SUCCESS;
+
+	if (strcasecmp(cli_data->in_type, "DotSO") == 0 || strcasecmp(cli_data->in_type, "JSON") == 0)
+		err = in_dotso_out_cli_exec_add(cli_data, argv);
+	else
+		err = EXIT_FAILURE;
+
+	return err;
+}
+
+static int in_dotso_out_cli_exec_del(cli_data_t *cli_data, char *argv[])
+{
+	int err = EXIT_SUCCESS;
+
+	cli_data->bbf_ctx.in_param = argv[0];
+
+	err = bbf_entry_method(&cli_data->bbf_ctx, BBF_DEL_OBJECT);
+	if (!err) {
+		printf("Deleted %s\n", cli_data->bbf_ctx.in_param);
+		bbf_entry_restart_services(NULL, true);
+	} else {
+		printf("ERROR: %d retrieving %s\n", err, cli_data->bbf_ctx.in_param);
+		bbf_entry_revert_changes(NULL);
+		err = EXIT_FAILURE;
+	}
+
+	return err;
+}
+
+static int cli_exec_del(cli_data_t *cli_data, char *argv[])
+{
+	int err = EXIT_SUCCESS;
+
+	if (strcasecmp(cli_data->in_type, "DotSO") == 0 || strcasecmp(cli_data->in_type, "JSON") == 0)
+		err = in_dotso_out_cli_exec_del(cli_data, argv);
+	else
+		err = EXIT_FAILURE;
+
+	return err;
+}
+
+static int in_dotso_out_cli_exec_instances(cli_data_t *cli_data, char *argv[])
+{
+	int err = EXIT_SUCCESS;
+
+	cli_data->bbf_ctx.in_param = argv[0];
+	cli_data->bbf_ctx.nextlevel = false;
+
+	err = bbf_entry_method(&cli_data->bbf_ctx, BBF_INSTANCES);
+	if (!err) {
+		struct dm_parameter *n;
+
+		list_for_each_entry(n, &cli_data->bbf_ctx.list_parameter, list) {
+			printf("%s\n", n->name);
+		}
+	} else {
+		printf("ERROR: %d retrieving %s\n", err, cli_data->bbf_ctx.in_param);
+		err = EXIT_FAILURE;
+	}
+
+	return err;
+}
+
+static int cli_exec_instances(cli_data_t *cli_data, char *argv[])
+{
+	int err = EXIT_SUCCESS;
+
+	if (strcasecmp(cli_data->in_type, "DotSO") == 0 || strcasecmp(cli_data->in_type, "JSON") == 0)
+		err = in_dotso_out_cli_exec_instances(cli_data, argv);
+	else
+		err = EXIT_FAILURE;
+
+	return err;
+}
+
+static int in_dotso_out_cli_exec_schema(cli_data_t *cli_data, char *argv[])
+{
+	int err = EXIT_SUCCESS;
+
+	cli_data->bbf_ctx.in_param = argv[0];
+	cli_data->bbf_ctx.nextlevel = false;
+	cli_data->bbf_ctx.iscommand = true;
+	cli_data->bbf_ctx.isevent = true;
+	cli_data->bbf_ctx.isinfo = true;
+
+	err = bbf_entry_method(&cli_data->bbf_ctx, BBF_SCHEMA);
+	if (!err) {
+		struct dm_parameter *n;
+
+	    printf("\nDumping %s Schema...\n\n", cli_data->bbf_ctx.in_param);
+
+		list_for_each_entry(n, &cli_data->bbf_ctx.list_parameter, list) {
+			int cmd = get_dm_type(n->type);
+
+			printf("%s\n", n->name);
+
+			if (cmd == DMT_COMMAND) {
+				if (n->data) {
+					const char **in, **out;
+					operation_args *args;
+					int i;
+
+					args = (operation_args *) n->data;
+					in = args->in;
+					if (in) {
+						for (i = 0; in[i] != NULL; i++)
+							printf("%s input:%s\n", n->name, in[i]);
+					}
+
+					out = args->out;
+					if (out) {
+						for (i = 0; out[i] != NULL; i++)
+							printf("%s output:%s\n", n->name, out[i]);
+					}
+				}
+			} else if (cmd == DMT_EVENT) {
+				if (n->data) {
+					event_args *ev;
+
+					ev = (event_args *)n->data;
+
+					if (ev->param) {
+						const char **in = ev->param;
+
+						for (int i = 0; in[i] != NULL; i++)
+							printf("%s event_arg:%s\n", n->name, in[i]);
+					}
+				}
+			}
+		}
+	} else {
+		printf("ERROR: %d retrieving %s\n", err, cli_data->bbf_ctx.in_param);
+		err = EXIT_FAILURE;
+	}
+
+	return err;
+}
+
+static int cli_exec_schema(cli_data_t *cli_data, char *argv[])
+{
+	int err = EXIT_SUCCESS;
+
+	if (strcasecmp(cli_data->in_type, "DotSO") == 0 || strcasecmp(cli_data->in_type, "JSON") == 0)
+		err = in_dotso_out_cli_exec_schema(cli_data, argv);
+	else
+		err = EXIT_FAILURE;
+
+	return err;
+}
+
+static int cli_exec_command(cli_data_t *cli_data, int argc, char *argv[])
+{
+	cli_cmd_t *cli_cmd = NULL;
+	int err = EXIT_SUCCESS;
+
+	cli_data->cmd = argv[0];
+	if (!cli_data->cmd || strlen(cli_data->cmd) == 0) {
+		return EXIT_FAILURE;
+	}
+
+	bbfdm_load_deamon_config();
+	bbf_ctx_init(&cli_data->bbf_ctx, DEAMON_DM_ROOT_OBJ, DEAMON_DM_VENDOR_EXTENSION, DEAMON_DM_VENDOR_EXTENSION_EXCLUDE);
+	if (DEAMON_DM_ROOT_OBJ == NULL) {
+		return EXIT_FAILURE;
+	}
+
+	cli_data->bbf_ctx.dm_type = cli_data->proto;
+	cli_data->bbf_ctx.instance_mode = cli_data->instance_mode;
+
+	for (size_t i = 0; i < ARRAY_SIZE(cli_commands); i++) {
+		cli_cmd = &cli_commands[i];
+		if (strcmp(cli_data->cmd, cli_cmd->name) == 0) {
+			if (argc-1 < cli_cmd->num_args) {
+				printf("ERROR: Number of arguments for %s method is wrong(%d), it should be %d\n", cli_cmd->name, argc-1, cli_cmd->num_args);
+				cli_commands[0].exec_cmd(cli_data, NULL);
+				err = EXIT_FAILURE;
+				goto end;
+			}
+
+			err = cli_cmd->exec_cmd(cli_data, &argv[1]);
+			break;
+		}
+	}
+
+end:
+	bbf_ctx_clean(&cli_data->bbf_ctx);
+	bbf_global_clean(DEAMON_DM_ROOT_OBJ);
+	return err;
+}
+
+int bbfdm_cli_exec_command(int argc, char *argv[])
+{
+	cli_data_t cli_data = {0};
+	int err = EXIT_SUCCESS;
+
+	// Exit if no command specified
+	if (argc < 1) {
+		printf("ERROR: command name not specified\n");
+		return EXIT_FAILURE;
+	}
+
+	memset(&cli_data, 0, sizeof(cli_data_t));
+	err = bbfdm_load_cli_config(&cli_data);
+	if (err) {
+		return EXIT_FAILURE;
+	}
+
+	err = cli_exec_command(&cli_data, argc, argv);
+
+	return err;
+}
diff --git a/daemon/json_rpc/cli.h b/daemon/json_rpc/cli.h
new file mode 100644
index 0000000000000000000000000000000000000000..8de5a90732d4ba5809e6d889843d144d356ee1ef
--- /dev/null
+++ b/daemon/json_rpc/cli.h
@@ -0,0 +1,11 @@
+/*
+ * cli.c: Cli command for bbfdmd
+ *
+ * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
+ *
+ * See LICENSE file for license related information.
+ */
+
+int bbfdm_cli_exec_command(int argc, char *argv[]);
diff --git a/daemon/json_rpc/common.c b/daemon/json_rpc/common.c
new file mode 100644
index 0000000000000000000000000000000000000000..483983235278f243ec8a45c53d0e6eff7b192e1e
--- /dev/null
+++ b/daemon/json_rpc/common.c
@@ -0,0 +1,152 @@
+/*
+ * common.c: Common utils of Get/Set/Operate handlers
+ *
+ * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: Vivek Dutta <vivek.dutta@iopsys.eu>
+ * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
+ * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu>
+ *
+ * See LICENSE file for license related information.
+ */
+
+#include "common.h"
+#include "get_helper.h"
+
+#define DEFAULT_LOG_LEVEL (2)
+
+static unsigned char gLogLevel = DEFAULT_LOG_LEVEL;
+
+// Logging utilities
+void set_debug_level(unsigned char level)
+{
+	gLogLevel = level;
+}
+
+void print_error(const char *format, ...)
+{
+	va_list arglist;
+
+	if (gLogLevel < 1)
+		return;
+
+	va_start(arglist, format);
+	vsyslog(LOG_ERR, format, arglist);
+	va_end(arglist);
+}
+
+void print_warning(const char *format, ...)
+{
+	va_list arglist;
+
+	if (gLogLevel < 2)
+		return;
+
+	va_start(arglist, format);
+	vsyslog(LOG_WARNING, format, arglist);
+	va_end(arglist);
+}
+
+void print_info(const char *format, ...)
+{
+	va_list arglist;
+
+	if (gLogLevel < 3)
+		return;
+
+	va_start(arglist, format);
+	vsyslog(LOG_INFO, format, arglist);
+	va_end(arglist);
+}
+
+void print_debug(const char *format, ...)
+{
+	va_list arglist;
+
+	if (gLogLevel < 4)
+		return;
+
+	va_start(arglist, format);
+	vsyslog(LOG_DEBUG, format, arglist);
+	va_end(arglist);
+}
+
+
+bool is_str_eq(const char *s1, const char *s2)
+{
+	if (strcmp(s1, s2) == 0)
+		return true;
+
+	return false;
+}
+
+bool get_boolean_string(char *value)
+{
+	if (!value)
+		return false;
+
+	if (strncasecmp(value, "true", 4) == 0 ||
+	    value[0] == '1' ||
+	    strncasecmp(value, "on", 2) == 0 ||
+	    strncasecmp(value, "yes", 3) == 0 ||
+	    strncasecmp(value, "enabled", 7) == 0)
+		return true;
+
+	return false;
+}
+
+
+
+int get_dm_type(char *dm_type)
+{
+	if (dm_type == NULL)
+		return DMT_STRING;
+
+	if (DM_STRCMP(dm_type, DMT_TYPE[DMT_STRING]) == 0)
+		return DMT_STRING;
+	else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_UNINT]) == 0)
+		return DMT_UNINT;
+	else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_INT]) == 0)
+		return DMT_INT;
+	else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_UNLONG]) == 0)
+		return DMT_UNLONG;
+	else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_LONG]) == 0)
+		return DMT_LONG;
+	else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_BOOL]) == 0)
+		return DMT_BOOL;
+	else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_TIME]) == 0)
+		return DMT_TIME;
+	else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_HEXBIN]) == 0)
+		return DMT_HEXBIN;
+	else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_BASE64]) == 0)
+		return DMT_BASE64;
+	else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_COMMAND]) == 0)
+		return DMT_COMMAND;
+	else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_EVENT]) == 0)
+		return DMT_EVENT;
+	else
+		return DMT_STRING;
+
+	return DMT_STRING;
+}
+
+eParamType get_eparam_type(char *dm_type, int *err)
+{
+	*err = 0;
+	switch (get_dm_type(dm_type))
+	{
+		case DMT_STRING: return PARAM_STRING;
+		case DMT_UNINT: return PARAM_UNSIGNED_INTEGER;
+		case DMT_INT: return PARAM_INTEGER;
+		case DMT_UNLONG: return PARAM_UNSIGNED_LONG;
+		case DMT_LONG: return PARAM_LONG;
+		case DMT_BOOL: return PARAM_BOOLEAN;
+		case DMT_HEXBIN: return PARAM_HEXBINARY;
+		case DMT_BASE64: return PARAM_BASE64;
+		default: break;
+	}
+	*err = -1;
+
+	return 0;
+}
+
diff --git a/daemon/json_rpc/common.h b/daemon/json_rpc/common.h
new file mode 100644
index 0000000000000000000000000000000000000000..a25891331a7f2024dc028dfa3892c1c137c08919
--- /dev/null
+++ b/daemon/json_rpc/common.h
@@ -0,0 +1,64 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <syslog.h>
+#include <regex.h>
+#include <sys/param.h>
+#include <string.h>
+
+#include <json_hal_common.h>
+
+#include "libdmtree/dmapi.h"
+
+#define ROOT_NODE "Device."
+#define BBF_ADD_EVENT "AddObj"
+#define BBF_DEL_EVENT "DelObj"
+#define BBF_EVENT "event"
+
+#define MAX_DM_KEY_LEN 256
+#define MAX_DM_PATH 1024
+#define MAX_DM_VALUE 4096
+#define DM_VALUE_SEP ","
+#define DELIM '.'
+
+extern DMOBJ *DEAMON_DM_ROOT_OBJ;
+extern DM_MAP_VENDOR *DEAMON_DM_VENDOR_EXTENSION[2];
+extern DM_MAP_VENDOR_EXCLUDE *DEAMON_DM_VENDOR_EXTENSION_EXCLUDE;
+
+bool is_str_eq(const char *s1, const char *s2);
+void set_debug_level(unsigned char level);
+void print_error(const char *format, ...);
+void print_warning(const char *format, ...);
+void print_info(const char *format, ...);
+void print_debug(const char *format, ...);
+bool get_boolean_string(char *value);
+
+int get_dm_type(char *dm_type);
+eParamType get_eparam_type(char *dm_type, int *err);
+
+#define DEBUG(fmt, args...) \
+	print_debug("[%s:%d]"fmt, __func__, __LINE__, ##args)
+
+#define INFO(fmt, args...) \
+	print_info(fmt, ##args)
+
+#define ERR(fmt, args...) \
+	print_error("[%s:%d] " fmt, __func__, __LINE__, ##args)
+
+#define WARNING(fmt, args...) \
+	print_warning("[%s:%d] " fmt, __func__, __LINE__, ##args)
+
+// glibc doesn't guarantee a 0 termianted string on strncpy
+// strncpy with always 0 terminated string
+static inline void strncpyt(char *dst, const char *src, size_t n)
+{
+        if (n > 1) {
+                strncpy(dst, src, n - 1);
+                dst[n - 1] = 0;
+        }
+}
+
+#endif /* COMMON_H */
diff --git a/daemon/json_rpc/event.c b/daemon/json_rpc/event.c
new file mode 100644
index 0000000000000000000000000000000000000000..8873a451803e1e7ca884d786f408b93d375e197e
--- /dev/null
+++ b/daemon/json_rpc/event.c
@@ -0,0 +1,93 @@
+/*
+ * event.c: event handler
+ *
+ * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu>
+ *
+ * See LICENSE file for license related information.
+ */
+#include "libdmtree/dmcommon.h"
+#include "event.h"
+#include <unistd.h>
+
+#define FIREWALL_RULE_DATA	"Device.Services.VoiceService.%d.X_RDK_Firewall_Rule_Data"
+#define FIREWALL_RULE_DATA_PATTERN "Device\\.Services\\.VoiceService\\.[0-9]+\\.X_RDK_Firewall_Rule_Data"
+
+int subs_event_handler(const json_object *jmsg, int param_count, json_object *jreply)
+{
+	int ret = RETURN_OK;
+	int param_index = 0;
+	hal_subscribe_event_request_t param_request;
+
+	if (jmsg == NULL || jreply == NULL) {
+		ERR("event handler: Invalid memory");
+		return RETURN_ERR;
+	}
+
+	memset(&param_request, 0, sizeof(param_request));
+
+	    for (param_index = 0; param_index < param_count; param_index++) {
+		    /* Unpack the request parameter */
+		    if (json_hal_get_subscribe_event_request((json_object *)jmsg,
+			    param_index, &param_request) != RETURN_OK) {
+			    INFO("Failed to get subscription data from the server");
+			    return RETURN_ERR;
+		    }
+
+		    if (!match(param_request.name, FIREWALL_RULE_DATA_PATTERN)) {
+			    ret = RETURN_ERR;
+			    WARNING("Unexpected event [%s][%d]", param_request.name, (int)param_request.type);
+		    }
+		    else
+			    INFO("Subscribed [%s][%d]", param_request.name, (int)param_request.type);
+	}
+
+	ret = json_hal_add_result_status(jreply, ret == RETURN_OK ? RESULT_SUCCESS :
+		RESULT_FAILURE);
+
+	INFO("[%s] Replly msg = %s", __FUNCTION__,
+		json_object_to_json_string_ext(jreply, JSON_C_TO_STRING_PRETTY));
+
+	return ret;
+}
+
+/*  Expected format of rule : enable/disable,protocol,port,ip;
+    Ex: 1,sip,5060,2a02:c69:fe02::4;
+    1,sip,5060,2a02:c69:fe02::4;1,rtp,50000,2a02:c69:fe02::4;
+    1,sip,5060,2a02:c69:fe02::4;0,rtp,50000,2a02:c69:fe02::4;1,rtp,50001,2a02:c69:fe02::4; */
+static void create_fw_rule_payload(char **buf, bool enable, char *protocol, int port, char *ip)
+{
+	dmasprintf(buf, "%d,%s,%d,%s;", enable, protocol, port, ip);
+}
+
+int send_fw_rule_event(bool enable, char *protocol, int port, char *ip, int voice_service_idx)
+{
+	int ret = 0;
+	char *fw_rule_path = NULL;
+	char *fw_rule = NULL;
+
+	create_fw_rule_payload(&fw_rule, enable, protocol, port, ip);
+	dmasprintf(&fw_rule_path, FIREWALL_RULE_DATA, voice_service_idx);
+
+	ret = (json_hal_server_publish_event(fw_rule_path, fw_rule) == RETURN_OK) ? 0 : -1;
+	dmfree(fw_rule_path);
+	dmfree(fw_rule);
+
+	return ret;
+}
+
+int send_fw_rules_clear_event(int voice_service_idx)
+{
+	int ret = 0;
+    	char *fw_rule_path = NULL;
+	char fw_rule[] = {0};
+
+	dmasprintf(&fw_rule_path, FIREWALL_RULE_DATA, voice_service_idx);
+
+	ret = (json_hal_server_publish_event(fw_rule_path, fw_rule) == RETURN_OK) ? 0 : -1;
+	dmfree(fw_rule_path);
+
+	return ret;
+}
+
diff --git a/daemon/json_rpc/event.h b/daemon/json_rpc/event.h
new file mode 100644
index 0000000000000000000000000000000000000000..39facd3b2f7634e123b36f1bb544449891a3c824
--- /dev/null
+++ b/daemon/json_rpc/event.h
@@ -0,0 +1,20 @@
+#ifndef EVENT_H
+#define EVENT_H
+
+#include <json_hal_server.h>
+#include "common.h"
+
+enum {
+	VOICE_CON_ENABLED,
+	VOICE_CON_PROTOCOL,
+	VOICE_CON_PORT,
+	VOICE_CON_IP,
+	_VOICE_CON_MAX
+};
+
+int subs_event_handler(const json_object *jmsg, int param_count, json_object *jreply);
+int send_fw_rule_event(bool enable, char *protocol, int port, char *ip, int voice_service_idx);
+int send_fw_rules_clear_event(int voice_service_idx);
+
+#endif /* EVENT_H */
+
diff --git a/daemon/json_rpc/get.c b/daemon/json_rpc/get.c
new file mode 100644
index 0000000000000000000000000000000000000000..91c78e3a22d094f6ba9f463438d4e899a263409e
--- /dev/null
+++ b/daemon/json_rpc/get.c
@@ -0,0 +1,106 @@
+/*
+ * get.c: Get handler for bbfdmd
+ *
+ * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu>
+ *
+ * See LICENSE file for license related information.
+ */
+
+#include "get.h"
+#include "get_helper.h"
+
+typedef int (resp_cb_t)(char *name, char *value, char *type, void *ctx);
+
+static int resp_cb(char *name, char *value, char *type, void *ctx)
+{
+	int ret;
+	hal_param_t param_response;
+	json_object *jreply = ctx;
+
+	strncpyt(param_response.name, name, sizeof(param_response.name));
+
+	param_response.type = get_eparam_type(type, &ret);
+	if (ret) {
+		ERR("Unsupported parameter type %s for %s", type, name);
+		return -1;
+	}
+
+	/* json rpc expects true/false value for boolean */
+	if (param_response.type == PARAM_BOOLEAN) {
+		if (strncmp(value, "1", 2) == 0) {
+			strncpyt(param_response.value, "true", sizeof(param_response.value));
+		} else if (strncmp(value, "0", 2) == 0) {
+			strncpyt(param_response.value, "false", sizeof(param_response.value));
+		} else {
+			strncpyt(param_response.value, value, sizeof(param_response.value));
+		}
+	} else {
+		strncpyt(param_response.value, value, sizeof(param_response.value));
+	}
+
+	if (json_hal_add_param(jreply, GET_RESPONSE_MESSAGE, &param_response) != RETURN_OK) {
+		ERR("Failed to add response for %s", name);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int get_value(hal_param_t *params, resp_cb_t resp_cb, void *ctx)
+{
+	struct dmctx bbf_ctx;
+	struct dm_parameter *n = NULL;
+	int ret = -1;
+
+	memset(&bbf_ctx, 0, sizeof(bbf_ctx));
+	bbf_init(&bbf_ctx);
+	bbf_ctx.in_param = params->name;
+	bbf_ctx.enable_plugins = true;
+
+	if ((ret = bbfdm_cmd_exec(&bbf_ctx, BBF_GET_VALUE))) {
+		ERR("Failed to get value for %s", params->name);
+		goto Exit;
+	}
+
+	INFO("Preparing result for %s", params->name);
+	list_for_each_entry(n, &bbf_ctx.list_parameter, list) {
+		if (resp_cb(n->name, n->data, n->type, ctx)) {
+			goto Exit;
+		}
+	}
+
+	ret = 0;
+Exit:
+	bbf_cleanup(&bbf_ctx);
+	return ret;
+}
+
+int bbfdm_get_value(const json_object *jmsg, int param_count,
+	json_object *jreply)
+{
+	int i;
+	hal_param_t param_request;
+
+	if (jmsg == NULL || jreply == NULL) {
+		ERR("invalid parameter");
+		return RETURN_ERR;
+	}
+
+	for (i = 0; i < param_count; i++) {
+		/* Unpack the JSON and populate the data into request_param object */
+		if (json_hal_get_param((json_object *)jmsg, i, GET_REQUEST_MESSAGE,
+			&param_request) != RETURN_OK) {
+			ERR("Failed to get parameter from json");
+			return RETURN_ERR;
+		}
+
+		if (get_value(&param_request, resp_cb, jreply)) {
+			ERR("Failed to get parameter value for %s", param_request.name);
+			return RETURN_ERR;
+		}
+	}
+
+	return RETURN_OK;
+}
diff --git a/daemon/json_rpc/get.h b/daemon/json_rpc/get.h
new file mode 100644
index 0000000000000000000000000000000000000000..624f11dd5120110b6a190d9a4f444ac5d3ec4851
--- /dev/null
+++ b/daemon/json_rpc/get.h
@@ -0,0 +1,12 @@
+#ifndef GET_H
+#define GET_H
+
+#include "common.h"
+#include <json_hal_server.h>
+
+
+int bbfdm_get_value(const json_object *jmsg, int param_count,
+	json_object *jreply);
+
+#endif /* GET_H */
+
diff --git a/daemon/json_rpc/get_helper.c b/daemon/json_rpc/get_helper.c
new file mode 100644
index 0000000000000000000000000000000000000000..007bbff7d47095623685cab0b1d88abf2e20fd72
--- /dev/null
+++ b/daemon/json_rpc/get_helper.c
@@ -0,0 +1,92 @@
+/*
+ * get_helper.c: Get Fast handler for bbfdmd
+ *
+ * Copyright (C) 2019-2023 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: Vivek Dutta <vivek.dutta@iopsys.eu>
+ * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu>
+ *
+ * See LICENSE file for license related information.
+ */
+
+#define _XOPEN_SOURCE
+#define _DEFAULT_SOURCE
+
+#include <time.h>
+#include <setjmp.h>
+
+#include "get_helper.h"
+#include "common.h"
+
+#include "libdmtree/dmentry.h"
+
+
+DMOBJ *DEAMON_DM_ROOT_OBJ = NULL;
+DM_MAP_VENDOR *DEAMON_DM_VENDOR_EXTENSION[2] = {0};
+DM_MAP_VENDOR_EXCLUDE *DEAMON_DM_VENDOR_EXTENSION_EXCLUDE = NULL;
+
+// uloop.h does not have versions, below line is to use
+// deprecated uloop_timeout_remaining for the time being
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+static jmp_buf gs_jump_location;
+static bool gs_jump_called_by_bbf = false;
+
+void handle_pending_signal(int sig)
+{
+	if (gs_jump_called_by_bbf) {
+		siglongjmp(gs_jump_location, 1);
+	}
+
+	ERR("Exception [%d] not cause by bbf dm, exit with error", sig);
+	exit(1);
+}
+
+int bbfdm_cmd_exec(struct dmctx *bbf_ctx, int cmd)
+{
+	int fault = 0;
+
+	if (bbf_ctx->in_param == NULL)
+		return USP_FAULT_INTERNAL_ERROR;
+
+	if (sigsetjmp(gs_jump_location, 1) == 0) {
+		gs_jump_called_by_bbf = true;
+		fault = bbf_entry_method(bbf_ctx, cmd);
+	} else {
+		ERR("PID [%ld]::Exception on [%d => %s]", getpid(), cmd, bbf_ctx->in_param);
+		fault = USP_FAULT_INTERNAL_ERROR;
+	}
+
+	gs_jump_called_by_bbf = false;
+
+	if (fault)
+		WARNING("Fault [%d => %d => %s]", fault, cmd, bbf_ctx->in_param);
+
+	return fault;
+}
+
+void bbf_init(struct dmctx *dm_ctx)
+{
+	bbf_ctx_init(dm_ctx, DEAMON_DM_ROOT_OBJ, DEAMON_DM_VENDOR_EXTENSION, DEAMON_DM_VENDOR_EXTENSION_EXCLUDE);
+}
+
+void bbf_cleanup(struct dmctx *dm_ctx)
+{
+	bbf_ctx_clean(dm_ctx);
+}
+
+void bbf_sub_init(struct dmctx *dm_ctx)
+{
+	bbf_ctx_init_sub(dm_ctx, DEAMON_DM_ROOT_OBJ, DEAMON_DM_VENDOR_EXTENSION, DEAMON_DM_VENDOR_EXTENSION_EXCLUDE);
+}
+
+void bbf_sub_cleanup(struct dmctx *dm_ctx)
+{
+	bbf_ctx_clean_sub(dm_ctx);
+}
+
+void bbf_commit()
+{
+	bbf_entry_restart_services(NULL, true);
+}
+
diff --git a/daemon/json_rpc/get_helper.h b/daemon/json_rpc/get_helper.h
new file mode 100644
index 0000000000000000000000000000000000000000..0ff7804c4a659c544b3298837c4f6e45dfaf9c63
--- /dev/null
+++ b/daemon/json_rpc/get_helper.h
@@ -0,0 +1,18 @@
+#ifndef GET_HELPER_H
+#define GET_HELPER_H
+
+#include <libubox/blobmsg.h>
+#include "common.h"
+#include "libdmtree/dmbbf.h"
+
+void handle_pending_signal(int sig);
+
+int bbfdm_cmd_exec(struct dmctx *bbf_ctx, int cmd);
+
+void bbf_init(struct dmctx *dm_ctx);
+void bbf_cleanup(struct dmctx *dm_ctx);
+void bbf_sub_init(struct dmctx *dm_ctx);
+void bbf_sub_cleanup(struct dmctx *dm_ctx);
+void bbf_commit();
+
+#endif /* GET_HELPER_H */
diff --git a/daemon/json_rpc/main.c b/daemon/json_rpc/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..a285a0a9e3aa776e5c72268155e901e143926875
--- /dev/null
+++ b/daemon/json_rpc/main.c
@@ -0,0 +1,229 @@
+/*
+ * main.c: Datamodel daemon
+ *
+ * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu>
+ *
+ * See LICENSE file for license related information.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <libubox/blobmsg.h>
+#include <libubox/uloop.h>
+#include <libubus.h>
+#include <sys/prctl.h>
+#include <sys/mman.h>
+
+#include "set.h"
+#include "get.h"
+#include "add_delete.h"
+#include "event.h"
+#include "get_helper.h"
+#include "cli.h"
+#include "libdmtree/dmentry.h"
+
+#define TELCOVOICEMGR_CONF_FILE "/etc/rdk/conf/telcovoice_manager_conf.json"
+
+extern struct list_head global_memhead;
+extern DM_MAP_OBJ tDynamicObj[];
+extern DM_MAP_VENDOR tVendorExtension[];
+
+static const char g_ubus_path[] = "voice.sip.data";
+
+int rpc_handler_init()
+{
+	if (json_hal_server_init(TELCOVOICEMGR_CONF_FILE) != RETURN_OK)	{
+		ERR("Failed to init HAL server");
+		return -1;
+	}
+
+	if (json_hal_server_register_action_callback("setParameters",
+		bbfdm_set_value) != RETURN_OK) {
+		ERR("Failed to register setParameters callback");
+		goto Error;
+	}
+
+	if (json_hal_server_register_action_callback("getParameters",
+		bbfdm_get_value) != RETURN_OK) {
+		ERR("Failed to register getParameters callback");
+		goto Error;
+	}
+
+	if (json_hal_server_register_action_callback("deleteObject",
+		bbfdm_del_object) != RETURN_OK) {
+		ERR("Failed to register deleteObject callback");
+		goto Error;
+	}
+	if (json_hal_server_register_action_callback("subscribeEvent",
+		subs_event_handler) != RETURN_OK) {
+		ERR("Failed to register subscribeEvent callback");
+		goto Error;
+	}
+
+	if (json_hal_server_run() != RETURN_OK) {
+		ERR("Failed to run HAL server");
+		goto Error;
+	}
+
+	return 0;
+
+Error:
+	json_hal_server_terminate();
+	return -1;
+}
+
+int rpc_handler_uninit()
+{
+	if (json_hal_server_terminate() != RETURN_OK) {
+		ERR("Failed to terminate HAL server");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void usage(char *prog)
+{
+	fprintf(stderr, "Usage: %s [options]\n", prog);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "options:\n");
+	fprintf(stderr, "    -c <command input>  Run cli command\n");
+	fprintf(stderr, "    -h                 Displays this help\n");
+	fprintf(stderr, "\n");
+}
+
+static void bbfdm_cleanup(void)
+{
+	bbf_global_clean(DEAMON_DM_ROOT_OBJ);
+}
+
+int bbfdm_load_deamon_config(void)
+{
+	DEAMON_DM_ROOT_OBJ = (DMOBJ *)dm_dynamic_calloc(&global_memhead, 2, sizeof(DMOBJ));
+	if (DEAMON_DM_ROOT_OBJ == NULL) {
+		fprintf(stderr, "ERROR: No Memory exists\n");
+		return -1;
+	}
+
+	char *node_obj = dm_dynamic_strdup(&global_memhead, tDynamicObj[0].path);
+	unsigned int len = strlen(node_obj);
+
+	node_obj[len-1] = 0;
+	DEAMON_DM_ROOT_OBJ[0].obj = node_obj; 
+	DEAMON_DM_ROOT_OBJ[0].nextobj = tDynamicObj[0].root_obj;
+	DEAMON_DM_ROOT_OBJ[0].leaf = tDynamicObj[0].root_leaf;
+	DEAMON_DM_ROOT_OBJ[0].permission = &DMREAD;
+	DEAMON_DM_ROOT_OBJ[0].bbfdm_type = BBFDM_BOTH;
+
+	DEAMON_DM_VENDOR_EXTENSION[0] = tVendorExtension;
+	//DEAMON_DM_VENDOR_EXTENSION[1] = tVendorExtensionOverwrite;
+	//DEAMON_DM_VENDOR_EXTENSION_EXCLUDE = tVendorExtensionExclude;
+
+	return 0;
+}
+
+static void program_exit(int ret)
+{
+	rpc_handler_uninit();
+	bbfdm_cleanup();
+	closelog();
+	uloop_done();
+	exit(ret);
+}
+
+static void sig_handler(__attribute__((unused)) int signum)
+{
+	program_exit(0);
+}
+
+static void signal_init()
+{
+	signal(SIGINT, sig_handler);
+}
+
+static void voice_event_cb(struct ubus_context *ctx __attribute__((unused)),
+		struct ubus_event_handler *ev __attribute__((unused)),
+		const char *type, struct blob_attr *msg)
+{
+	const struct blobmsg_policy policy[] = {
+		[VOICE_CON_ENABLED] = { .name = "enabled", .type = BLOBMSG_TYPE_BOOL},
+		[VOICE_CON_PROTOCOL] = { .name = "protocol", .type = BLOBMSG_TYPE_STRING},
+		[VOICE_CON_PORT] = { .name = "port", .type = BLOBMSG_TYPE_INT32},
+		[VOICE_CON_IP] = { .name = "ip", .type = BLOBMSG_TYPE_STRING},
+	};
+	struct blob_attr *tb[_VOICE_CON_MAX];
+
+	if (type && strcmp(type, g_ubus_path) != 0)
+		return;
+
+	if (blobmsg_parse(policy, _VOICE_CON_MAX, tb, blob_data(msg), blob_len(msg))){
+		ERR("Failed to parse blob");
+		return;
+	}
+
+	send_fw_rule_event(blobmsg_get_bool(tb[VOICE_CON_ENABLED]),
+		blobmsg_get_string(tb[VOICE_CON_PROTOCOL]),
+		blobmsg_get_u32(tb[VOICE_CON_PORT]),
+		blobmsg_get_string(tb[VOICE_CON_IP]), 1);
+}
+
+int main(int argc, char **argv)
+{
+	int err = 0, ch;
+	struct ubus_context *ubus_ctx = NULL;
+	struct ubus_event_handler add_event = {};
+
+	signal_init();
+
+	while ((ch = getopt(argc, argv, "h:c:")) != -1) {
+		switch (ch) {
+		case 'c':
+			err = bbfdm_cli_exec_command(argc-optind+1, &argv[optind-1]);
+			exit(err);
+		case 'h':
+			usage(argv[0]);
+			exit(0);
+		default:
+			break;
+		}
+	}
+
+	openlog(argv[0], LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
+
+	err = bbfdm_load_deamon_config();
+	if (err) {
+		ERR("Failed to configure DM");
+		goto Exit;
+	}
+
+	err = rpc_handler_init();
+	if (err) {
+		ERR("Voice HAL Server Initialization Failed");
+		goto Exit;
+	}
+
+	uloop_init();
+
+	ubus_ctx = ubus_connect(NULL);
+	if (!ubus_ctx) {
+		ERR("Failed to connect to ubus");
+		return -1;
+	}
+
+	ubus_add_uloop(ubus_ctx);
+	add_event.cb = voice_event_cb;
+	if (ubus_register_event_handler(ubus_ctx, &add_event, g_ubus_path))
+		ERR("Failed to connect to ubus");
+
+	INFO("Waiting on uloop....");
+	uloop_run();
+
+Exit:
+	ubus_shutdown(ubus_ctx);
+	program_exit(err);
+
+	return err;
+}
diff --git a/daemon/json_rpc/service_helper.c b/daemon/json_rpc/service_helper.c
new file mode 100644
index 0000000000000000000000000000000000000000..610332ea89e0cae5170f4c9d2f8583619d0f8b14
--- /dev/null
+++ b/daemon/json_rpc/service_helper.c
@@ -0,0 +1,70 @@
+/*
+ * service_helper.c: helper functions for managing services
+ *
+ * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * See LICENSE file for license related information.
+ */
+
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <libubox/blobmsg.h>
+#include "common.h"
+#include "event.h"
+#include "libdmtree/dmentry.h"
+#include "libdmtree/dmcommon.h"
+
+#define SERVICE_RESTART_DELAY_SEC 10
+
+static void timer_handler(union sigval sv)
+{
+	(void)sv;
+
+	send_fw_rules_clear_event(1);
+
+	dm_uci_init();
+	bbf_entry_restart_services(NULL, false);
+	dm_uci_exit();
+
+	INFO("Restart services");
+
+	dmcmd("/bin/systemctl", 2, "restart", "voicemngr");
+#ifdef DM_ENABLE_DECT
+	dmcmd("/bin/systemctl", 2, "restart", "dectmngr");
+#endif
+	dmcmd("/bin/systemctl", 2, "restart", "asterisk");
+}
+
+int restart_services()
+{
+	static timer_t timerid;
+	static bool init;
+	struct sigevent sev;
+	struct itimerspec trigger;
+
+	if (!init) {
+		memset(&sev, 0, sizeof(struct sigevent));
+		sev.sigev_notify = SIGEV_THREAD;
+		sev.sigev_notify_function = &timer_handler;
+
+		if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) != 0) {
+			ERR("Failed to create timer, err: %s (%d)", strerror(errno), errno);
+			return -1;
+		}
+
+		init = true;
+	}
+
+	// delay restart to accumulate all changes
+	memset(&trigger, 0, sizeof(struct itimerspec));
+	trigger.it_value.tv_sec = SERVICE_RESTART_DELAY_SEC;
+	if (timer_settime(timerid, 0, &trigger, NULL) != 0) {
+		ERR("Failed to set timer, err: %s (%d)", strerror(errno), errno);
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/daemon/json_rpc/service_helper.h b/daemon/json_rpc/service_helper.h
new file mode 100644
index 0000000000000000000000000000000000000000..2700e97c7380459f90a2e83709bfe2ee48ddd956
--- /dev/null
+++ b/daemon/json_rpc/service_helper.h
@@ -0,0 +1,14 @@
+/*
+ * service_helper.h: helper functions for managing services
+ *
+ * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * See LICENSE file for license related information.
+ */
+
+#ifndef SERVICE_HELPER_H
+#define SERVICE_HELPER_H
+
+int restart_services();
+
+#endif /* SERVICE_HELPER_H */
diff --git a/daemon/json_rpc/set.c b/daemon/json_rpc/set.c
new file mode 100644
index 0000000000000000000000000000000000000000..bff95536a7fc062b113d489b9d051e1ef07d3cd7
--- /dev/null
+++ b/daemon/json_rpc/set.c
@@ -0,0 +1,63 @@
+/*
+ * set.c: Set handler for bbfdmd
+ *
+ * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu>
+ *
+ * See LICENSE file for license related information.
+ */
+
+#include "set.h"
+#include "add_delete.h"
+#include "get_helper.h"
+#include "service_helper.h"
+
+int bbfdm_set_value(const json_object *jmsg, int param_count,
+	json_object *jreply)
+{
+	int i;
+	int fault;
+	hal_param_t param;
+	struct dmctx bbf_ctx;
+
+	if (jmsg == NULL || jreply == NULL) {
+		ERR("setParameters cb: invalid memory");
+		return RETURN_ERR;
+	}
+
+	for (i = 0; i < param_count; i++) {
+		/* Unpack the JSON and polulate the data into request_param object */
+		if (json_hal_get_param((json_object *)jmsg, i, SET_REQUEST_MESSAGE,
+			&param) != RETURN_OK) {
+			ERR("setParameters cb: failed get parameter");
+			return RETURN_ERR;
+		}
+
+		memset(&bbf_ctx, 0, sizeof(bbf_ctx));
+		bbf_init(&bbf_ctx);
+		bbf_ctx.in_param = param.name;
+		bbf_ctx.in_value = param.value;
+
+		fault = bbfdm_cmd_exec(&bbf_ctx, BBF_SET_VALUE);
+		/* Try to add a new object and try to set the value again */
+		if (fault == FAULT_9005 && !bbfdm_add_object(&bbf_ctx))
+			fault = bbfdm_cmd_exec(&bbf_ctx, BBF_SET_VALUE);
+		if (fault)
+			ERR("setParameters cb: failed setting (%s) (%s)", param.name, param.value);
+
+		bbf_cleanup(&bbf_ctx);
+
+		/* Pack the json response and reply back. */
+		if (json_hal_add_result_status(jreply, fault == 0 ? RESULT_SUCCESS :
+			RESULT_FAILURE) != RETURN_OK) {
+			ERR("setParameters cb: failed setting status");
+			return RETURN_ERR;
+		}
+	}
+
+	restart_services();
+
+	return RETURN_OK;
+}
+
diff --git a/daemon/json_rpc/set.h b/daemon/json_rpc/set.h
new file mode 100644
index 0000000000000000000000000000000000000000..2375a66c124fbb820b496a9eb81fbd2a0cc4c220
--- /dev/null
+++ b/daemon/json_rpc/set.h
@@ -0,0 +1,11 @@
+#ifndef SET_H
+#define SET_H
+
+#include "common.h"
+#include <json_hal_server.h>
+
+int bbfdm_set_value(const json_object *jmsg, int param_count,
+	json_object *jreply);
+
+#endif /* SET_H */
+
diff --git a/libdm/dmtree/servicesvoiceservice.c b/libdm/dmtree/servicesvoiceservice.c
index 1336318151d6087ff36501f142a8d31b2c2cb116..71ad320c5b5e9ffddaafc12e7acceaadec0294cd 100644
--- a/libdm/dmtree/servicesvoiceservice.c
+++ b/libdm/dmtree/servicesvoiceservice.c
@@ -241,12 +241,49 @@ static int get_ServicesVoiceService_CallLogNumberOfEntries(char *refparam, struc
 	return 0;
 }
 
+static int get_ServicesVoiceHalInit(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
+{
+    	struct uci_section *s;
+
+	if ((s = is_dmmap_section_exist("dmmap_voice_hal_init", "general")))
+	    *value = dmuci_get_value_by_section_fallback_def(s, "init_done", "0");
+
+	return 0;
+}
+
+static int set_ServicesVoiceHalInit(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
+{
+	bool b;
+	struct uci_section *dmmap = NULL, *s = NULL, *stmp = NULL;
+
+	switch (action) {
+		case VALUECHECK:
+			if (dm_validate_boolean(value))
+				return FAULT_9007;
+		case VALUESET:
+			if (!(dmmap = is_dmmap_section_exist("dmmap_voice_hal_init", "general"))) {
+				dmuci_add_section("voice_hal_init", "general", &s);
+				dmuci_add_section_bbfdm("dmmap_voice_hal_init", "general", &dmmap);
+				dmuci_set_value_by_section(dmmap, "section_name", section_name(s));
+			}
+			string_to_bool(value, &b);
+			uci_foreach_sections_safe("voice_hal_init", "general", stmp, s) {
+				get_dmmap_section_of_config_section("dmmap_voice_hal_init", "general", section_name(s), &dmmap);
+				dmuci_set_value_by_section(dmmap, "init_done", b ? "1" : "0");
+				dmuci_set_value_by_section(s, "init_done", b ? "1" : "0");
+			}
+
+			return 0;
+	}
+	return 0;
+}
+
 /**********************************************************************************************************************************
 *                                            OBJ & PARAM DEFINITION
 ***********************************************************************************************************************************/
 DM_MAP_OBJ tDynamicObj[] = {
 /* parentobj, nextobject, parameter */
-{"Device.Services.", tServicesObj, NULL},
+{"Device.Services.", tServicesObj, tServicesVoiceHalParams},
 {0}
 };
 
@@ -278,3 +315,7 @@ DMLEAF tServicesVoiceServiceParams[] = {
 {"CallLogNumberOfEntries", &DMREAD, DMT_UNINT, get_ServicesVoiceService_CallLogNumberOfEntries, NULL, BBFDM_BOTH},
 {0}
 };
+
+DMLEAF tServicesVoiceHalParams[] = {
+{BBF_VENDOR_PREFIX"VoiceHalInit", &DMWRITE, DMT_BOOL, get_ServicesVoiceHalInit, set_ServicesVoiceHalInit, BBFDM_BOTH},
+};
diff --git a/libdm/dmtree/servicesvoiceservice.h b/libdm/dmtree/servicesvoiceservice.h
index c1064e0563348a9bcab457b30a112bb5567b093b..6912ab8145ac88f1bb431df84ec4a7f222d8cc04 100644
--- a/libdm/dmtree/servicesvoiceservice.h
+++ b/libdm/dmtree/servicesvoiceservice.h
@@ -30,6 +30,7 @@ extern DMLEAF tServicesVoiceServiceVoIPProfileParams[];
 extern DMLEAF tServicesVoiceServiceCodecProfileParams[];
 extern DMOBJ tServicesVoiceServiceDECTObj[];
 extern DMLEAF tServicesVoiceServiceDECTParams[];
+extern DMLEAF tServicesVoiceHalParams[];
 
 int browseVoiceServiceSIPProviderInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance);
 int delObjVoiceServiceSIPProvider(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action);