You can use serde attribute with and just use a intermediate structure letting the real implementation to serde:
use core::ops::Range;
use serde::{Deserialize, Serialize};
use serde_json::Error;
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
struct Foo {
    name: String,
    value: i32,
    #[serde(with = "range_aux", flatten)]
    bound: Range<i32>,
}
mod range_aux {
    use core::ops::Range;
    use serde::{Deserialize, Deserializer, Serialize, Serializer};
    #[derive(Serialize, Deserialize)]
    struct RangeAux {
        upper_bound: i32,
        lower_bound: i32,
    }
    pub fn serialize<S>(range: &Range<i32>, ser: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        RangeAux::serialize(
            &RangeAux {
                upper_bound: range.end,
                lower_bound: range.start,
            },
            ser,
        )
    }
    pub fn deserialize<'de, D>(d: D) -> Result<Range<i32>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let range_aux: RangeAux = RangeAux::deserialize(d)?;
        Ok(Range {
            start: range_aux.lower_bound,
            end: range_aux.upper_bound,
        })
    }
}
fn main() -> Result<(), Error> {
    let data = r#"{"name":"foo","value":1234,"upper_bound":5000,"lower_bound":1000}"#;
    let foo: Foo = serde_json::from_str(data)?;
    assert_eq!(
        foo,
        Foo {
            name: "foo".to_string(),
            value: 1234,
            bound: 1000..5000
        }
    );
    let output = serde_json::to_string(&foo)?;
    assert_eq!(data, output);
    Ok(())
}
That very close to remote pattern but this doesn't work with generic see serde#1844.
A possible generic version:
use core::ops::Range;
use serde::{Deserialize, Serialize};
use serde_json::Error;
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
struct Foo {
    name: String,
    value: i32,
    #[serde(with = "range_aux", flatten)]
    bound: Range<i32>,
}
mod range_aux {
    use core::ops::Range;
    use serde::{Deserialize, Deserializer, Serialize, Serializer};
    pub fn serialize<S, Idx: Serialize>(range: &Range<Idx>, ser: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        // could require Idx to be Copy or Clone instead of borrowing Idx
        #[derive(Serialize)]
        struct RangeAux<'a, Idx> {
            upper_bound: &'a Idx,
            lower_bound: &'a Idx,
        }
        RangeAux::serialize(
            &RangeAux {
                upper_bound: &range.end,
                lower_bound: &range.start,
            },
            ser,
        )
    }
    pub fn deserialize<'de, D, Idx: Deserialize<'de>>(d: D) -> Result<Range<Idx>, D::Error>
    where
        D: Deserializer<'de>,
    {
        #[derive(Deserialize)]
        struct RangeAux<Idx> {
            upper_bound: Idx,
            lower_bound: Idx,
        }
        let range_aux: RangeAux<Idx> = RangeAux::deserialize(d)?;
        Ok(Range {
            start: range_aux.lower_bound,
            end: range_aux.upper_bound,
        })
    }
}
fn main() -> Result<(), Error> {
    let data = r#"{"name":"foo","value":1234,"upper_bound":5000,"lower_bound":1000}"#;
    let foo: Foo = serde_json::from_str(data)?;
    assert_eq!(
        foo,
        Foo {
            name: "foo".to_string(),
            value: 1234,
            bound: 1000..5000
        }
    );
    let output = serde_json::to_string(&foo)?;
    assert_eq!(data, output);
    Ok(())
}