diff --git a/opentelemetry-otlp/CHANGELOG.md b/opentelemetry-otlp/CHANGELOG.md
index 347a759004..ca17eb2f1c 100644
--- a/opentelemetry-otlp/CHANGELOG.md
+++ b/opentelemetry-otlp/CHANGELOG.md
@@ -5,6 +5,8 @@
 ### Fixed
 
 - URL encoded values in `OTEL_EXPORTER_OTLP_HEADERS` are now correctly decoded. [#1578](https://github.com/open-telemetry/opentelemetry-rust/pull/1578)
+- OTLP exporter will not change the URL added through `ExportConfig` [#1706](https://github.com/open-telemetry/opentelemetry-rust/pull/1706)
+- Default grpc endpoint will not have path based on signal(e.g `/v1/traces`) [#1706](https://github.com/open-telemetry/opentelemetry-rust/pull/1706)
 
 ### Added
 
diff --git a/opentelemetry-otlp/src/exporter/http/mod.rs b/opentelemetry-otlp/src/exporter/http/mod.rs
index fc46953ed1..a5ced848d4 100644
--- a/opentelemetry-otlp/src/exporter/http/mod.rs
+++ b/opentelemetry-otlp/src/exporter/http/mod.rs
@@ -1,4 +1,7 @@
-use super::{default_headers, default_protocol, parse_header_string};
+use super::{
+    default_headers, default_protocol, parse_header_string,
+    OTEL_EXPORTER_OTLP_HTTP_ENDPOINT_DEFAULT,
+};
 use crate::{
     ExportConfig, Protocol, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS,
     OTEL_EXPORTER_OTLP_TIMEOUT,
@@ -150,7 +153,7 @@ impl HttpExporterBuilder {
         signal_timeout_var: &str,
         signal_http_headers_var: &str,
     ) -> Result<OtlpHttpClient, crate::Error> {
-        let endpoint = resolve_endpoint(
+        let endpoint = resolve_http_endpoint(
             signal_endpoint_var,
             signal_endpoint_path,
             self.exporter_config.endpoint.as_str(),
@@ -373,10 +376,10 @@ fn build_endpoint_uri(endpoint: &str, path: &str) -> Result<Uri, crate::Error> {
 }
 
 // see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#endpoint-urls-for-otlphttp
-fn resolve_endpoint(
+fn resolve_http_endpoint(
     signal_endpoint_var: &str,
     signal_endpoint_path: &str,
-    provided_or_default_endpoint: &str,
+    provided_endpoint: &str,
 ) -> Result<Uri, crate::Error> {
     // per signal env var is not modified
     if let Some(endpoint) = env::var(signal_endpoint_var)
@@ -394,8 +397,14 @@ fn resolve_endpoint(
         return Ok(endpoint);
     }
 
-    // if neither works, we use the one provided in pipeline. If user never provides one, we will use the default one
-    build_endpoint_uri(provided_or_default_endpoint, signal_endpoint_path)
+    if provided_endpoint.is_empty() {
+        build_endpoint_uri(
+            OTEL_EXPORTER_OTLP_HTTP_ENDPOINT_DEFAULT,
+            signal_endpoint_path,
+        )
+    } else {
+        provided_endpoint.parse().map_err(From::from)
+    }
 }
 
 #[allow(clippy::mutable_key_type)] // http headers are not mutated
@@ -411,16 +420,19 @@ fn add_header_from_string(input: &str, headers: &mut HashMap<HeaderName, HeaderV
 #[cfg(test)]
 mod tests {
     use crate::exporter::tests::run_env_test;
-    use crate::{OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT};
+    use crate::{
+        new_exporter, WithExportConfig, OTEL_EXPORTER_OTLP_ENDPOINT,
+        OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
+    };
 
-    use super::build_endpoint_uri;
+    use super::{build_endpoint_uri, resolve_http_endpoint};
 
     #[test]
     fn test_append_signal_path_to_generic_env() {
         run_env_test(
             vec![(OTEL_EXPORTER_OTLP_ENDPOINT, "http://example.com")],
             || {
-                let endpoint = super::resolve_endpoint(
+                let endpoint = resolve_http_endpoint(
                     OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
                     "/v1/traces",
                     "http://localhost:4317",
@@ -436,7 +448,7 @@ mod tests {
         run_env_test(
             vec![(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, "http://example.com")],
             || {
-                let endpoint = super::resolve_endpoint(
+                let endpoint = super::resolve_http_endpoint(
                     OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
                     "/v1/traces",
                     "http://localhost:4317",
@@ -455,7 +467,7 @@ mod tests {
                 (OTEL_EXPORTER_OTLP_ENDPOINT, "http://wrong.com"),
             ],
             || {
-                let endpoint = super::resolve_endpoint(
+                let endpoint = super::resolve_http_endpoint(
                     OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
                     "/v1/traces",
                     "http://localhost:4317",
@@ -469,10 +481,13 @@ mod tests {
     #[test]
     fn test_use_provided_or_default_when_others_missing() {
         run_env_test(vec![], || {
-            let endpoint =
-                super::resolve_endpoint("NON_EXISTENT_VAR", "/v1/traces", "http://localhost:4317")
-                    .unwrap();
-            assert_eq!(endpoint, "http://localhost:4317/v1/traces");
+            let endpoint = super::resolve_http_endpoint(
+                "NON_EXISTENT_VAR",
+                "/v1/traces",
+                "http://localhost:4317",
+            )
+            .unwrap();
+            assert_eq!(endpoint, "http://localhost:4317/");
         });
     }
 
@@ -501,7 +516,7 @@ mod tests {
                 (OTEL_EXPORTER_OTLP_ENDPOINT, "http://example.com"),
             ],
             || {
-                let endpoint = super::resolve_endpoint(
+                let endpoint = super::resolve_http_endpoint(
                     OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
                     "/v1/traces",
                     "http://localhost:4317",
@@ -515,7 +530,7 @@ mod tests {
     #[test]
     fn test_all_invalid_urls_falls_back_to_error() {
         run_env_test(vec![], || {
-            let result = super::resolve_endpoint(
+            let result = super::resolve_http_endpoint(
                 OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
                 "/v1/traces",
                 "-*/*-/*-//-/-/yet-another-invalid-uri",
@@ -610,4 +625,37 @@ mod tests {
             }
         }
     }
+
+    #[test]
+    fn test_http_exporter_endpoint() {
+        // default endpoint should add signal path
+        run_env_test(vec![], || {
+            let exporter = new_exporter().http();
+
+            let url = resolve_http_endpoint(
+                OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
+                "/v1/traces",
+                exporter.exporter_config.endpoint.as_str(),
+            )
+            .unwrap();
+
+            assert_eq!(url, "http://localhost:4318/v1/traces");
+        });
+
+        // if builder endpoint is set, it should not add signal path
+        run_env_test(vec![], || {
+            let exporter = new_exporter()
+                .http()
+                .with_endpoint("http://localhost:4318/v1/tracesbutnotreally");
+
+            let url = resolve_http_endpoint(
+                OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
+                "/v1/traces",
+                exporter.exporter_config.endpoint.as_str(),
+            )
+            .unwrap();
+
+            assert_eq!(url, "http://localhost:4318/v1/tracesbutnotreally");
+        });
+    }
 }
diff --git a/opentelemetry-otlp/src/exporter/mod.rs b/opentelemetry-otlp/src/exporter/mod.rs
index 6be463ef9d..8df736870f 100644
--- a/opentelemetry-otlp/src/exporter/mod.rs
+++ b/opentelemetry-otlp/src/exporter/mod.rs
@@ -58,6 +58,7 @@ pub const OTEL_EXPORTER_OTLP_TIMEOUT: &str = "OTEL_EXPORTER_OTLP_TIMEOUT";
 pub const OTEL_EXPORTER_OTLP_TIMEOUT_DEFAULT: u64 = 10;
 
 // Endpoints per protocol https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md
+#[cfg(feature = "grpc-tonic")]
 const OTEL_EXPORTER_OTLP_GRPC_ENDPOINT_DEFAULT: &str = "http://localhost:4317";
 const OTEL_EXPORTER_OTLP_HTTP_ENDPOINT_DEFAULT: &str = "http://localhost:4318";
 
@@ -69,7 +70,8 @@ pub(crate) mod tonic;
 /// Configuration for the OTLP exporter.
 #[derive(Debug)]
 pub struct ExportConfig {
-    /// The base address of the OTLP collector. If not set, the default address is used.
+    /// The address of the OTLP collector. If it's not provided via builder or environment variables.
+    /// Default address will be used based on the protocol.
     pub endpoint: String,
 
     /// The protocol to use when communicating with the collector.
@@ -84,7 +86,9 @@ impl Default for ExportConfig {
         let protocol = default_protocol();
 
         ExportConfig {
-            endpoint: default_endpoint(protocol),
+            endpoint: "".to_string(),
+            // don't use default_endpoint(protocol) here otherwise we
+            // won't know if user provided a value
             protocol,
             timeout: Duration::from_secs(OTEL_EXPORTER_OTLP_TIMEOUT_DEFAULT),
         }
@@ -128,15 +132,6 @@ fn default_protocol() -> Protocol {
     }
 }
 
-/// default endpoint for protocol
-fn default_endpoint(protocol: Protocol) -> String {
-    match protocol {
-        Protocol::Grpc => OTEL_EXPORTER_OTLP_GRPC_ENDPOINT_DEFAULT.to_string(),
-        Protocol::HttpBinary => OTEL_EXPORTER_OTLP_HTTP_ENDPOINT_DEFAULT.to_string(),
-        Protocol::HttpJson => OTEL_EXPORTER_OTLP_HTTP_ENDPOINT_DEFAULT.to_string(),
-    }
-}
-
 /// default user-agent headers
 #[cfg(any(feature = "grpc-tonic", feature = "http-proto", feature = "http-json"))]
 fn default_headers() -> std::collections::HashMap<String, String> {
@@ -183,7 +178,7 @@ impl HasExportConfig for HttpExporterBuilder {
 /// # }
 /// ```
 pub trait WithExportConfig {
-    /// Set the address of the OTLP collector. If not set, the default address is used.
+    /// Set the address of the OTLP collector. If not set or set to empty string, the default address is used.
     fn with_endpoint<T: Into<String>>(self, endpoint: T) -> Self;
     /// Set the protocol to use when communicating with the collector.
     ///
@@ -297,10 +292,7 @@ mod tests {
     fn test_default_http_endpoint() {
         let exporter_builder = crate::new_exporter().http();
 
-        assert_eq!(
-            exporter_builder.exporter_config.endpoint,
-            "http://localhost:4318"
-        );
+        assert_eq!(exporter_builder.exporter_config.endpoint, "");
     }
 
     #[cfg(feature = "grpc-tonic")]
@@ -308,10 +300,7 @@ mod tests {
     fn test_default_tonic_endpoint() {
         let exporter_builder = crate::new_exporter().tonic();
 
-        assert_eq!(
-            exporter_builder.exporter_config.endpoint,
-            "http://localhost:4317"
-        );
+        assert_eq!(exporter_builder.exporter_config.endpoint, "");
     }
 
     #[test]
diff --git a/opentelemetry-otlp/src/exporter/tonic/mod.rs b/opentelemetry-otlp/src/exporter/tonic/mod.rs
index 61e142e743..244d16b62d 100644
--- a/opentelemetry-otlp/src/exporter/tonic/mod.rs
+++ b/opentelemetry-otlp/src/exporter/tonic/mod.rs
@@ -11,7 +11,7 @@ use tonic::transport::Channel;
 #[cfg(feature = "tls")]
 use tonic::transport::ClientTlsConfig;
 
-use super::{default_headers, parse_header_string};
+use super::{default_headers, parse_header_string, OTEL_EXPORTER_OTLP_GRPC_ENDPOINT_DEFAULT};
 use crate::exporter::Compression;
 use crate::{
     ExportConfig, OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_ENDPOINT,
@@ -149,7 +149,6 @@ impl Default for TonicExporterBuilder {
         TonicExporterBuilder {
             exporter_config: ExportConfig {
                 protocol: crate::Protocol::Grpc,
-                endpoint: crate::exporter::default_endpoint(crate::Protocol::Grpc),
                 ..Default::default()
             },
             tonic_config,
@@ -213,7 +212,6 @@ impl TonicExporterBuilder {
     fn build_channel(
         self,
         signal_endpoint_var: &str,
-        signal_endpoint_path: &str,
         signal_timeout_var: &str,
         signal_compression_var: &str,
         signal_headers_var: &str,
@@ -255,12 +253,24 @@ impl TonicExporterBuilder {
         }
 
         let config = self.exporter_config;
+
+        // resolving endpoint string
+        // grpc doesn't have a "path" like http(See https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md)
+        // the path of grpc calls are based on the protobuf service definition
+        // so we won't append one for default grpc endpoints
+        // If users for some reason want to use a custom path, they can use env var or builder to pass it
         let endpoint = match env::var(signal_endpoint_var)
             .ok()
             .or(env::var(OTEL_EXPORTER_OTLP_ENDPOINT).ok())
         {
             Some(val) => val,
-            None => format!("{}{signal_endpoint_path}", config.endpoint),
+            None => {
+                if config.endpoint.is_empty() {
+                    OTEL_EXPORTER_OTLP_GRPC_ENDPOINT_DEFAULT.to_string()
+                } else {
+                    config.endpoint
+                }
+            }
         };
 
         let endpoint = Channel::from_shared(endpoint).map_err(crate::Error::from)?;
@@ -300,7 +310,6 @@ impl TonicExporterBuilder {
 
         let (channel, interceptor, compression) = self.build_channel(
             crate::logs::OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
-            "/v1/logs",
             crate::logs::OTEL_EXPORTER_OTLP_LOGS_TIMEOUT,
             crate::logs::OTEL_EXPORTER_OTLP_LOGS_COMPRESSION,
             crate::logs::OTEL_EXPORTER_OTLP_LOGS_HEADERS,
@@ -323,7 +332,6 @@ impl TonicExporterBuilder {
 
         let (channel, interceptor, compression) = self.build_channel(
             crate::metric::OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
-            "/v1/metrics",
             crate::metric::OTEL_EXPORTER_OTLP_METRICS_TIMEOUT,
             crate::metric::OTEL_EXPORTER_OTLP_METRICS_COMPRESSION,
             crate::metric::OTEL_EXPORTER_OTLP_METRICS_HEADERS,
@@ -347,7 +355,6 @@ impl TonicExporterBuilder {
 
         let (channel, interceptor, compression) = self.build_channel(
             crate::span::OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
-            "/v1/traces",
             crate::span::OTEL_EXPORTER_OTLP_TRACES_TIMEOUT,
             crate::span::OTEL_EXPORTER_OTLP_TRACES_COMPRESSION,
             crate::span::OTEL_EXPORTER_OTLP_TRACES_HEADERS,