diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs
index df73785222..7db3c89064 100644
--- a/lib/ain-grpc/src/lib.rs
+++ b/lib/ain-grpc/src/lib.rs
@@ -52,11 +52,15 @@ pub fn add_grpc_server(_runtime: &Runtime, _addr: &str) -> Result<(), Box<dyn Er
     Ok(())
 }
 
-pub fn init_runtime() {
-    log::info!("Starting gRPC and JSON RPC servers");
+pub fn init(_argc: i32, _argv: &[&str]) {
     LogBuilder::from_env(Env::default().default_filter_or(Level::Info.as_str()))
         .target(Target::Stdout)
         .init();
+    log::info!("Initializing");
+}
+
+pub fn init_evm_runtime() {
+    log::info!("Initializing evm runtime");
     let _ = &*RUNTIME;
 }
 
diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs
index bff36b8cd7..4ccd6b8964 100644
--- a/lib/ain-rs-exports/src/lib.rs
+++ b/lib/ain-rs-exports/src/lib.rs
@@ -4,6 +4,8 @@ use ain_grpc::*;
 use ain_evm::runtime::RUNTIME;
 use log::debug;
 use std::error::Error;
+use std::ffi::CStr;
+use std::os::raw::c_char;
 
 use ethereum::{EnvelopedEncodable, TransactionAction, TransactionSignature};
 use primitive_types::{H160, H256, U256};
@@ -41,7 +43,8 @@ pub mod ffi {
             miner_address: [u8; 20],
         ) -> Result<Vec<u8>>;
 
-        fn init_runtime();
+        unsafe fn init(_argc: i32, _argv: *const *const c_char);
+        fn init_evm_runtime();
         fn start_servers(json_addr: &str, grpc_addr: &str) -> Result<()>;
         fn stop_runtime();
 
@@ -157,3 +160,12 @@ fn evm_finalize(
             .finalize_block(context, update_state, difficulty, Some(eth_address))?;
     Ok(block.header.rlp_bytes().into())
 }
+
+/// # Safety
+/// Ensure that argc passed counts the exact number of argument variables that is passed into init
+pub unsafe fn init(argc: i32, argv: *const *const c_char) {
+    let args: Vec<&str> = (0..argc)
+        .map(|i| unsafe { CStr::from_ptr(*argv.add(i as usize)).to_str().unwrap() })
+        .collect();
+    ain_grpc::init(argc, &args);
+}
diff --git a/src/defid.cpp b/src/defid.cpp
index ad8718b62b..b31f75fb7c 100644
--- a/src/defid.cpp
+++ b/src/defid.cpp
@@ -60,6 +60,7 @@ static void WaitForShutdown()
 //
 static bool AppInit(int argc, char* argv[])
 {
+    init(argc, argv);
     InitInterfaces interfaces;
     interfaces.chain = interfaces::MakeChain();
 
@@ -163,6 +164,8 @@ static bool AppInit(int argc, char* argv[])
             // If locking the data directory failed, exit immediately
             return false;
         }
+        
+        init_evm_runtime();
         fRet = AppInitMain(interfaces);
     }
     catch (const std::exception& e) {
diff --git a/src/init.cpp b/src/init.cpp
index cdc6c9aea3..5190942012 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -638,8 +638,10 @@ void SetupServerArgs()
     gArgs.AddArg("-dftxworkers=<n>", strprintf("No. of parallel workers associated with the DfTx related work pool. Stock splits, parallel processing of the chain where appropriate, etc use this worker pool (default: %d)", DEFAULT_DFTX_WORKERS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     gArgs.AddArg("-maxaddrratepersecond=<n>", strprintf("Sets MAX_ADDR_RATE_PER_SECOND limit for ADDR messages(default: %f)", MAX_ADDR_RATE_PER_SECOND), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     gArgs.AddArg("-maxaddrprocessingtokenbucket=<n>", strprintf("Sets MAX_ADDR_PROCESSING_TOKEN_BUCKET limit for ADDR messages(default: %d)", MAX_ADDR_PROCESSING_TOKEN_BUCKET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
+    gArgs.AddArg("-grpcbind=<addr>[:port]", "Bind to given address to listen for JSON-gRPC connections. Do not expose the gRPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -grpcport. This option can be specified multiple times (default: 127.0.0.1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
     gArgs.AddArg("-grpcport=<port>", strprintf("Start GRPC connections on <port> and <port + 1> (default: %u, testnet: %u, devnet: %u, regtest: %u)", defaultBaseParams->GRPCPort(), testnetBaseParams->GRPCPort(), devnetBaseParams->GRPCPort(), regtestBaseParams->GRPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
-    gArgs.AddArg("-ethrpcport=<port>", strprintf("Listen for ETH-JASON-RPC connections on <port>> (default: %u, testnet: %u, devnet: %u, regtest: %u)", defaultBaseParams->ETHRPCPort(), testnetBaseParams->ETHRPCPort(), devnetBaseParams->ETHRPCPort(), regtestBaseParams->ETHRPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
+    gArgs.AddArg("-ethrpcbind=<addr>[:port]", "Bind to given address to listen for ETH-JSON-RPC connections. Do not expose the ETH-RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -ethrpcport. This option can be specified multiple times (default: 127.0.0.1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
+    gArgs.AddArg("-ethrpcport=<port>", strprintf("Listen for ETH-JSON-RPC connections on <port>> (default: %u, testnet: %u, devnet: %u, regtest: %u)", defaultBaseParams->ETHRPCPort(), testnetBaseParams->ETHRPCPort(), devnetBaseParams->ETHRPCPort(), regtestBaseParams->ETHRPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
 
 #if HAVE_DECL_DAEMON
     gArgs.AddArg("-daemon", "Run in the background as a daemon and accept commands", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -1553,11 +1555,53 @@ bool AppInitMain(InitInterfaces& interfaces)
 
     // ********************************************************* Step 4b: application initialization
 
-    init_runtime();
-    int grpc_port = gArgs.GetArg("-grpcport", BaseParams().GRPCPort());
+    /* Start the ETH RPC and gRPC servers. Current API only allows for one ETH 
+     * RPC/gRPC server to bind to one address. By default, we will only take 
+     * the first address, if multiple addresses are specified.
+    */
     int eth_rpc_port = gArgs.GetArg("-ethrpcport", BaseParams().ETHRPCPort());
-    start_servers("127.0.0.1:" + std::to_string(eth_rpc_port), "127.0.0.1:" +  std::to_string(grpc_port));
+    int grpc_port = gArgs.GetArg("-grpcport", BaseParams().GRPCPort());
+    std::vector<std::pair<std::string, uint16_t> > eth_endpoints;
+    std::vector<std::pair<std::string, uint16_t> > g_endpoints;
+
+    // Determine which addresses to bind to ETH RPC server
+    if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-ethrpcbind"))) { // Default to loopback if not allowing external IPs
+        eth_endpoints.push_back(std::make_pair("127.0.0.1", eth_rpc_port));
+        if (gArgs.IsArgSet("-rpcallowip")) {
+            LogPrintf("WARNING: option -rpcallowip was specified without -ethrpcbind; this doesn't usually make sense\n");
+        }
+        if (gArgs.IsArgSet("-ethrpcbind")) {
+            LogPrintf("WARNING: option -ethrpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
+        }
+    } else if (gArgs.IsArgSet("-ethrpcbind")) { // Specific bind address
+        for (const std::string& strETHRPCBind : gArgs.GetArgs("-ethrpcbind")) {
+            int port = eth_rpc_port;
+            std::string host;
+            SplitHostPort(strETHRPCBind, port, host);
+            eth_endpoints.push_back(std::make_pair(host, port));
+        }
+    }
+
+    // Determine which addresses to bind to gRPC server
+    if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-grpcbind"))) { // Default to loopback if not allowing external IPs
+        g_endpoints.push_back(std::make_pair("127.0.0.1", grpc_port));
+        if (gArgs.IsArgSet("-rpcallowip")) {
+            LogPrintf("WARNING: option -rpcallowip was specified without -grpcbind; this doesn't usually make sense\n");
+        }
+        if (gArgs.IsArgSet("-grpcbind")) {
+            LogPrintf("WARNING: option -grpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
+        }
+    } else if (gArgs.IsArgSet("-grpcbind")) { // Specific bind address
+        for (const std::string& strGRPCBind : gArgs.GetArgs("-grpcbind")) {
+            int port = grpc_port;
+            std::string host;
+            SplitHostPort(strGRPCBind, port, host);
+            g_endpoints.push_back(std::make_pair(host, port));
+        }
+    }
 
+    // Default to using the first address passed to bind to ETH RPC server and gRPC server
+    start_servers(eth_endpoints[0].first + ":" + std::to_string(eth_endpoints[0].second), g_endpoints[0].first + "." + std::to_string(g_endpoints[0].second));
 
     // ********************************************************* Step 5: verify wallet database integrity
     for (const auto& client : interfaces.chain_clients) {